Haskell函数用于列表长度

时间:2016-01-02 09:25:39

标签: haskell fold

要使用折叠器计算列表的长度,可以执行以下操作:

foldr (\_ acc -> acc + 1) 0

进一步扩展折叠函数需要递增第二个参数的想法,我想出了这个(这是错误的):

foldr ((+1) . (flip const)) 0`

对该类型的进一步检查揭示了这一点:

(+1) . (flip const) :: Num (c -> c) => a -> c -> c

Haskell higher order function to calculate length 在那个页面上有一个有趣的评论,我真的无法理解

foldr (((+1).).(flip const)) 0

有人可以解释一下这个作文是如何起作用的吗?

2 个答案:

答案 0 :(得分:7)

首先,让我们关注foldr ((+1) . (flip const)) 0错误的原因。您只想增加第二个参数而忘记第一个参数。在语义上,那是

\_ a -> a + 1

但是,您写了以下内容:

(+1) . flip const
= (+1) . (\_ a -> a)
= \x -> (+1) . (\_ a -> a) $ x
= \x -> (+1) $ (\_ a -> a) $ x
= \x -> (+1) $ \a -> a
= \_ -> (+1) (\a -> a)
= const ( (+1) (\a -> a))

这就是您突然需要Num (c -> c)的原因,因为您正试图在(+1)上应用id

但实际上你的意思是:

\_ a -> a + 1
= \_ a -> (+1) a
= \_   -> (+1)
= const (+1)

毕竟,你想忘记第一个参数,并在第二个参数上使用函数f。您所需要做的就是使用const f

作文((+1).).(flip const)过于冗长,可能由pointfree生成:

((+1).).(flip const)
= ((\x -> x + 1).) . (\a _ -> a)
= \c -> ((\x -> x + 1).) . (\a _ -> a) $ c
= \c -> ((\x -> x + 1).) $ \_ -> c
= \c -> \f -> (\x -> x + 1) . f $ \_ -> c
= \c ->   (\x -> x + 1) . \_ -> c
= \_ c -> (\x -> x + 1) $ c
= \_ c -> c + 1

答案 1 :(得分:3)

这真的是一个评论,但对于一个人来说太长了。

除非你处理像懒惰Nat这样奇怪的数字,否则你真的想要

length xs = foldl' (\acc _ -> 1 + acc) 0 xs

让这毫无意义,

length = foldl' (\acc -> const ((1+) acc)) 0
length = foldl' (const . (1+)) 0

如果您愿意,可以将原始foldl'表达式转换为foldr形式,如下所示:

length xs = foldr go id xs 0 where
  go _ r acc = r $! 1 + acc

咀嚼go

go _ r acc = ($!) r $ (+) 1 acc
go _ r = ($!) r . (+1)
go _ r = (. (+1)) (($!) r)
go _ = (. (+1)) . ($!)
go = const ((. (+1)) . ($!))

咀嚼length

length = flip (foldr go id) 0

全部放在一起,

length = flip (foldr (const ((. (+1)) . ($!))) id) 0

我,其中一个,发现这种无点形式完全不透明。