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)
不幸的是,这似乎产生了一个非常巨大的结果。我什至无法在合理的时间内计算出树最左边的叶子。这有多大的表达?随着更多仿函数的分层,它增长的速度有多快?
最佳答案
无穷。以下术语循环您的重写器:
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)
的六个步骤之后出现的。)关于haskell - 需要多少 fmap?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/55566397/