After reading (and implementing) part of http://blog.sumtypeofway.com/recursion-schemes-part-2/ I still wonder how the types in the cata
function work. The cata
function is defined as:
mystery :: Functor f => (f a -> a) -> Term f -> a
mystery f = f . fmap (mystery f) . unTerm
I have something like Term Expr
. After unpacking I get Expr (Term Expr)
. The algebra (f
) is defined e.g. as f :: Expr Int -> Int
. I know I could call the following easily:
x = Literal "literal" :: Expr a
f :: Expr Int -> Int
f x :: Int
I can also imagine:
x = Literal "literal" :: Expr (Term Expr)
f :: Expr a -> Int
f x :: Int
But the following I suppose wouldn't work:
x = Literal "literal" :: Expr (Term Expr)
f :: Expr Int -> Int
f x :: ???
However, I still don't get how it works in the cata
function - how do I get from Expr (Term Expr)
to Expr a
. I understand that the values do work, but I just don't get the types - what happens in the leaves of the tree? This is indeed a mystery
...
Edit: I'll try to state more clearly what I don't understand.
Mentally, the cata
seems to work this way:
fmap f
to leaves. Expr Int
and I can call fmap f
to the node I have and get way up.It doesn't obviously work this way as I am applying fmap (cata f)
. However, ultimately the function f
gets called with Expr Int
as an argument (in the leaves). How was this type produced from Expr (Term Expr)
that it was before?
答案 0 :(得分:1)
这就是cata
对树叶的操作方式。
假设f :: Expr Int -> Int
。然后:
cata f :: Term Expr -> Int
fmap (cata f) :: Expr (Term Expr) -> Expr Int
现在,对于任何函数g :: a -> b
,我们都有
fmap g :: Expr a -> Expr b
fmap g (Literal n) = Literal n
...
因此,在文字上,g
并不重要。这意味着,选择a ~ Term Expr
,b ~ Int
和g = cata f
我们有
fmap (cata f) (Literal n) = Literal n :: Term Int
f (fmap (cata f) (Literal n)) = f (Literal n) :: Int
因此,粗略地说,在离开fmap (cata f)
上是一个无操作,但它会将类型从Expr (Term Expr)
更改为Expr Int
。对于任何Literal n :: Expr a
a
,这是一个微不足道的转变。