/ / Warum kann ich eine Musterfamilie in einer Musterfamilie nicht zuordnen? - Haskell, Typen

Warum kann ich bei einer Typfamilie kein Mustervergleich durchführen? - Haskell, Typen

Betrachten Sie den folgenden Code:

{-# LANGUAGE TypeFamilies #-}

data Twothings a b = Twothings a b

type family Leftthing a where
Leftthing (Twothings a b) = Leftthing a
Leftthing a = a

leftthing :: a -> Leftthing a
leftthing (Twothings a b) = leftthing a
leftthing b = b

Es wird nicht mit dem folgenden Fehler kompiliert:

Couldn"t match expected type ‘a’
with actual type ‘Twothings a0 t0’
‘a’ is a rigid type variable bound by
the type signature for:
leftthing :: forall a. a -> Leftthing a

Es beschwert sich über die Linie leftthing (Twothings a b) = leftthing a. Wenn ich richtig verstehe, kann es die Typvariable nicht vereinheitlichen a in der Typ-Signatur mit dem Typ des Konstruktors Twothings. Ok, das scheint Sinn zu ergeben. Aber dann, Wie kann ich jemals eine Funktion mit Typfamilien in der Typ-Signatur definieren??

Antworten:

11 für die Antwort № 1

Wenn Sie deklarieren

leftthing :: a -> Leftthing a

Sie sagen, dass die Anrufer von leftthing kann wählen was a ist.

Wenn du dann schreibst

leftthing (Twothings a b) = leftthing a

Du bist Vermutung dass sie ein gewählt haben Twothings geben Sie ein, und da dies nicht unbedingt der Fall ist, wird Ihr Programm abgelehnt.

Sie haben vielleicht gedacht, dass Sie es waren Testen ob sie hatten eine gewählt Twothings Tipp, aber nein! Typinformationen werden vor der Laufzeit gelöscht, daher gibt es keine Möglichkeit, einen solchen Test durchzuführen.

Sie kann Versuchen Sie, die erforderlichen Informationen zur Laufzeit wiederherzustellen. Lassen Sie mich zuerst die Inkonsistenz zwischen Ihren Leftthing und leftthing.

type family Leftthing a where
Leftthing (Twothings a b) = Leftthing{-you forgot the recursion!-} a
Leftthing a = a

Jetzt können wir die GADT von Zeugen definieren Twothingness.

data IsItTwothings :: * -> * where
YesItIs   :: IsItTwothings a -> IsItTwothings (Twothings a b)
NoItIsn"t :: Leftthing a ~ a => IsItTwothings a
-- ^^^^^^^^^^^^^^^ this constraint will hold for any type
-- which is *definitely not* a Twothings type

Und dann können wir den Zeugen als Argument übergeben:

leftthing :: IsItTwothings a -> a -> Leftthing a
leftthing (YesItIs r) (Twothings a b) = leftthing r a
leftthing NoItIsn"t   b               = b

In der Tat ist der Zeuge die unäre Kodierung der Anzahl der linksverschachtelten TwothingsEs ist die Wurzel deines Typs. Das ist genug Information, um zur Laufzeit die richtige Menge an Entpackung zu bestimmen.

> leftthing (YesItIs (YesItIs NoItIsn"t)) (Twothings (Twothings True 11) (Twothings "strange" [42]))
True

Zusammenfassend kann man keinen Typ nach Muster herausfindenpassend zu einem Wert. Stattdessen müssen Sie den Typ kennen, der für die Mustererkennung verwendet werden soll (da der Typ das Speicherlayout bestimmt und keine Laufzeittyp-Tags vorhanden sind). Sie können Muster nicht direkt auf Typen abgleichen (weil sie nur nicht dafür vorgesehen sind). Sie können Datentypen konstruieren, die als Laufzeitnachweis für die Typstruktur dienen und diese stattdessen abgleichen.

Vielleicht wird Ihr Programm eines Tages funktionieren, wenn Sie es dem Typ geben

leftthing :: pi a. a -> Leftthing a

woher pi ist der abhängige Quantifizierer und gibt an, dass das Argument des versteckten Typs nicht gelöscht wird, sondern zur Laufzeit weitergegeben und abgeglichen wird. Dieser Tag ist noch nicht gekommen, aber ich denke es wird.