需要多少张fmap?

dfe*_*uer 4 haskell

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)

认识到了(->) afmap = (.)你可以把它写

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)

不幸的是,这似乎产生了巨大的结果。我什至无法在合理的时间内计算出树的最左边的叶子。这种表达有多大?随着更多的函子层叠,它会增长多快?

Dan*_*ner 5

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).)