У меня есть рекурсивный тип данных, который имеет экземпляр Functor:Как предоставить экземпляр Functor для типа данных, созданного для общих схем рекурсии?
data Expr1 a
= Val1 a
| Add1 (Expr1 a) (Expr1 a)
deriving (Eq, Show, Functor)
Теперь, я заинтересован в изменении этого типа данных для поддержки общих схем рекурсии, как они описаны в this tutorial и this Hackage package. Мне удалось получить катаморфизм к работе:
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
имел. Кажется, что это своего рода несоответствие при попытке определить экземпляр функтора:
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))
но тогда это Newtype должно быть развернута, чтобы быть переданы cata
, что я не очень люблю. Я также не знаю, можно ли автоматически получить экземпляр-функтор Expr2
, как я сделал с Expr1
.
Я не думаю, что это можно сделать так, а не с псевдонимом типа, который вы пытаетесь сделать. –
@LouisWasserman: Предполагая, что в конечном итоге я использую newtype для 'Expr2', есть ли способ, чтобы экземпляр functor был получен автоматически, как я сделал с' Expr1'? – hugomg
Вы не можете получить экземпляр functor, полученный автоматически для чего-то типа 'newtype Expr a = Expr (Fix (ExprF a))' потому что 'Fix' не является функтором. Если вы измените его на 'data Fix fa = Fix (f (Fix fa)), то вы * можете * написать экземпляр functor, который выглядит как« instance functor f => Functor (Fix f) », и вам не нужно Новый тип. – user2407038