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/

10-12 20:31