Ich versuche, die Assoziativität von Listen auf Typebene so zu beweisen, dass ich zwischen äquivalenten Typen konvertieren kann, ohne Einschränkungen mitzunehmen.
Angenommen, die Standarddefinition der Verkettung:
type family (++) (xs :: [k]) (ys :: [k]) :: [k] where
'[] ++ ys = ys
(x ': xs) ++ ys = x ': (xs ++ ys)
Angenommen, ich habe eine Funktion:
given :: forall k (a :: [k]) (b :: [k]) (c :: [k]). Proxy ((a ++ b) ++ c)
given = Proxy -- Proxy is just an example
und ich möchte diese Funktion aufrufen und dann Assoziativität verwenden:
my :: forall k (a :: [k]) (b :: [k]) (c :: [k]). Proxy (a ++ (b ++ c))
my = given @k @a @b @c -- Couldn't match type ‘(a ++ b) ++ c’ with ‘a ++ (b ++ c)’
Diese Typgleichheit ist in der Tat nicht trivial, daher ist es keine Überraschung, dass der Compiler sie nicht versteht, aber ich kann es beweisen! Leider weiß ich nicht, wie ich den Compiler davon überzeugen kann, dass ich es kann.
Mein natürlicher erster Gedanke ist, etwas zu tun wie:
proof :: forall k (a :: [k]) (b :: [k]) (c :: [k]). (a ++ (b ++ c)) :~: ((a ++ b) ++ c)
proof = _
und dann ändere meine Funktion in:
my :: forall k (a :: [k]) (b :: [k]) (c :: [k]). Proxy (a ++ (b ++ c))
my = case proof @k @a @b @c of Refl -> given @k @a @b @c
Aber ich muss noch definieren proof
und dafür muss ich eine Induktion für seine Typargumente durchführen. Die einzige Möglichkeit, Induktionen für Typen in Haskell durchzuführen, die ich kenne, besteht darin, eine Typklasse zu definieren, aber dann muss ich dem Typ von die entsprechende Einschränkung hinzufügen my
, die ich nicht tun möchte - die Tatsache, dass sie aufgerufen wird given
und erzwingt, dass das Ergebnis ein „Implementierungsdetail“ ist.
Gibt es eine Möglichkeit, diese Art der Typengleichheit in Haskell zu beweisen, ohne auf unsichere Postulate zurückzugreifen?
(a++(b++c)) :~: ((a++b)++c)
ohne weitere Singleton-Argumente oder Typklasseneinschränkungen schreiben können .Antworten:
Nein, Sie können dies nicht ohne eine Einschränkung der Typklasse beweisen, da dies nicht der Fall ist. Hier ist insbesondere ein Gegenbeispiel:
Um die (dumme) Existenz von auszuschließen
Any
, müssen Sie eine Typklasse verwenden, die keineAny
Instanz hat. keine andere Wahl.quelle
Any
:(. Ich hatte gehofft, dass die freundlichen Anmerkungen in meiner Definition von++
garantieren würden, dass es wahr ist, aber dies wirdAny
deutlichAny
Grunde nicht nurundefined
aber auf Typebene? Da es moralisch korrekt ist, so zu tun, als gäbe es das letztere nicht, warum können wir das nicht auch für das erstere tun?unsafeCoerce
. Aber die Frage fordert ausdrücklich zu vermeidenunsafeCoerce
, und so können wir doch nicht so tun.