У меня есть рекурсивный тип данных, который имеет экземпляр Functor:
data Expr1 a
= Val1 a
| Add1 (Expr1 a) (Expr1 a)
deriving (Eq, Show, Functor)
Теперь я заинтересован в модификации этого типа данных для поддержки общих схем рекурсии, поскольку они описаны в этот учебник и этот пакет Hackage. Мне удалось заставить катаморфизм работать:
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))))
Но теперь я не могу понять, как дать Expr2
тот же экземпляр функтора, что и исходный Expr
. Кажется, существует некоторая несоответствие при попытке определить экземпляр functor:
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))'
Как написать экземпляр Functor для Expr2
?
Я думал об обертке Expr2 в newtype с newtype Expr2 a = Expr2 (Fix (ExprF a))
, но затем этот новый тип должен быть распакован для передачи в cata
, что мне не очень нравится. Я также не знаю, можно ли автоматически получить экземпляр функтора Expr2
, как я сделал с Expr1
.