需要多少张fmap?

时间:2019-04-08 04:46:31

标签: haskell

丹尼尔·瓦格纳(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

认识到(->) afmap = (.)可以编写

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)

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

1 个答案:

答案 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)的六个步骤之后产生的。)