Ich habe einen rekursiven Datentypen, die eine Functor Instanz hat:Wie gebe ich eine Funktor-Instanz an einen Datentyp, der für allgemeine Rekursionssysteme erstellt wurde?
data Expr1 a
= Val1 a
| Add1 (Expr1 a) (Expr1 a)
deriving (Eq, Show, Functor)
Nun, ich habe Interesse an Änderung dieser Datentyp zu unterstützen allgemeine Rekursion-Schemata, wie sie beschrieben sind in this tutorial und this Hackage package. Ich schaffte es die catamorphism zur Arbeit zu kommen:
newtype Fix f = Fix {unFix :: f (Fix f)}
data ExprF a r
= Val a
| Add r r
deriving (Eq, Show, Functor)
type Expr2 a = Fix (ExprF a)
cata :: Functor f => (f a -> a) -> Fix f -> a
cata f = f . fmap (cata f) . unFix
eval :: Expr2 Int -> Int
eval = cata $ \case
Val n -> n
Add x y -> x + y
main :: IO()
main =
print $ eval
(Fix (Add (Fix (Val 1)) (Fix (Val 2))))
Aber jetzt kann ich nicht herausfinden, wie Expr2
das gleiche Funktors Beispiel zu geben, dass die ursprünglichen Expr
hatte. Es scheint, es ist eine Art Nichtübereinstimmung ist beim Versuch, die Funktors Instanz zu definieren:
instance Functor (Fix (ExprF a)) where
fmap = undefined
Kind mis-match
The first argument of `Functor' should have kind `* -> *',
but `Fix (ExprF a)' has kind `*'
In the instance declaration for `Functor (Fix (ExprF a))'
Wie schreibe ich eine Functor Instanz für Expr2
?
Ich dachte über Ausdr2 in einem newtype mit newtype Expr2 a = Expr2 (Fix (ExprF a))
Einwickeln aber dann muss diese newtype ausgepackt werden, um cata
weitergegeben werden, was ich nicht sehr gut gefällt. Ich weiß auch nicht, ob es möglich wäre, die Funktorinstanz Expr2
automatisch so abzuleiten, wie ich es mit Expr1
gemacht habe.
Ich denke nicht, dass es so gemacht werden kann, nicht mit einem Typ-Alias, wie Sie es versuchen. –
@LouisWasserman: Angenommen, ich verwende einen neuen Typ für 'Expr2', gibt es eine Möglichkeit, die Funktorinstanz automatisch wie bei' Expr1' abzuleiten? – hugomg
Sie können die funktor-Instanz nicht automatisch für etwas wie "newtype Expr a = Expr (Fix (ExprF a))" ableiten, weil "Fix" kein Funktor ist. Wenn Sie es in 'data Fix fa = Fix (f (Fix fa))' ändern, dann können Sie * eine Funktorinstanz schreiben, die aussieht wie 'instance Functor f => Functor (Fix f) 'und Sie brauchen kein a neuer Typ. – user2407038