Daniel Wagner 的评论使我想到了这个问题。让我们从过度简化开始。假设你有一个类型
data Foo a = Foo [a]
Run Code Online (Sandbox Code Playgroud)
然后您可以编写Functor实例
instance Functor Foo where
fmap f (Foo l) = Foo (fmap f l)
Run Code Online (Sandbox Code Playgroud)
您可以将右侧重写为
Foo . fmap f $ l
Run Code Online (Sandbox Code Playgroud)
认识到了(->) a,fmap = (.)你可以把它写
fmap Foo (fmap f) l
Run Code Online (Sandbox Code Playgroud)
重复,你得到
fmap (fmap Foo) fmap f l
Run Code Online (Sandbox Code Playgroud)
所以,最后,
fmap f (Foo l) =
fmap fmap fmap Foo fmap f l
Run Code Online (Sandbox Code Playgroud)
如果选择一个稍微复杂一点的函子怎么办?
data Bar = Bar [Maybe a]
instance Functor Bar where
fmap f (Bar l) = Bar (fmap (fmap f) l)
Run Code Online (Sandbox Code Playgroud)
我开始手动执行此操作,但此操作开始失控,因此我切换为自动。
infixl 9 :@
data Expr
= BAR | F | L | FMap | Expr :@ Expr
deriving (Show)
rewrite :: Expr -> Expr
rewrite (p :@ (q :@ r))
= rewrite $ FMap :@ p :@ q :@ r
rewrite (p :@ q) = rewrite p :@ q
rewrite e = e
main = print $ rewrite $
BAR :@ (FMap :@ (FMap :@ F) :@ L)
Run Code Online (Sandbox Code Playgroud)
不幸的是,这似乎产生了巨大的结果。我什至无法在合理的时间内计算出树的最左边的叶子。这种表达有多大?随着更多的函子层叠,它会增长多快?
Infinite. The following term loops your rewriter:
FMap :@ ((FMap :@ (FMap :@ FMap)) :@ FMap)
Run Code Online (Sandbox Code Playgroud)
It does so in just three steps, which are:
((FMap :@ FMap) :@ (FMap :@ (FMap :@ FMap))) :@ FMap
(((FMap :@ (FMap :@ FMap)) :@ FMap) :@ (FMap :@ FMap)) :@ FMap
(((FMap :@ ((FMap :@ (FMap :@ FMap)) :@ FMap)) :@ FMap) :@ FMap) :@ FMap
Run Code Online (Sandbox Code Playgroud)
This last has the original term at its head. (The original looping term itself arises after six steps of rewriting your BAR :@ (FMap :@ (FMap :@ F) :@ L).)