丹尼尔·瓦格纳(Daniel Wagner)的comment使我想到了这个问题。让我们从过度简化开始。假设您有一个类型
data Foo a = Foo [a]
然后您可以编写Functor
实例
instance Functor Foo where
fmap f (Foo l) = Foo (fmap f l)
您可以将右侧重写为
Foo . fmap f $ l
认识到(->) a
,fmap = (.)
可以编写
fmap Foo (fmap f) l
重复,您得到
fmap (fmap Foo) fmap f l
最后,
fmap f (Foo l) =
fmap fmap fmap Foo fmap f l
如果您选择一个稍微复杂些的函子怎么办?
data Bar = Bar [Maybe a]
instance Functor Bar where
fmap f (Bar l) = Bar (fmap (fmap f) l)
我开始手动执行此操作,但是它开始失去控制,所以我切换到自动。
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)
不幸的是,这似乎产生了巨大的结果。我什至无法在合理的时间内计算出树的最左边的叶子。这种表达有多大?随着更多函子的层叠,它会增长多快?
答案 0 :(得分:5)
无限。以下术语循环您的重写器:
FMap :@ ((FMap :@ (FMap :@ FMap)) :@ FMap)
它只需三个步骤即可完成操作,
((FMap :@ FMap) :@ (FMap :@ (FMap :@ FMap))) :@ FMap
(((FMap :@ (FMap :@ FMap)) :@ FMap) :@ (FMap :@ FMap)) :@ FMap
(((FMap :@ ((FMap :@ (FMap :@ FMap)) :@ FMap)) :@ FMap) :@ FMap) :@ FMap
这最后一个字是原始术语。 (原始循环术语本身是在重写BAR :@ (FMap :@ (FMap :@ F) :@ L)
的六个步骤之后产生的。)