Haskell:foldr vs foldr1

min*_*nus 7 haskell fold

如果我有这个插入功能:

insert x []     = [x]
insert x (h:t)
  | x <= h      = x:(h:t)
  | otherwise   = h:(insert x t)
Run Code Online (Sandbox Code Playgroud)

这会产生一个排序列表:

foldr insert [] [1,19,-2,7,43]
Run Code Online (Sandbox Code Playgroud)

但是这个:

foldr1 insert [1,19,-2,7,43]
Run Code Online (Sandbox Code Playgroud)

产生' 不能构造无限类型:a0 = [a0] '

我很困惑为什么第二个电话无法工作.

我已经查看了foldrfoldr1的定义,并使用简单的算术函数进行了跟踪,但我仍然无法清楚地解释为什么第二次调用失败.

dav*_*420 16

我们来看一些类型的签名.

foldr  :: (a -> b -> b) -> b -> [a] -> b
foldr1 :: (a -> a -> a) ->      [a] -> a
Run Code Online (Sandbox Code Playgroud)

在这两种情况下,第一个参数是两个参数的函数.

  • 因为foldr1,这两个参数必须具有相同的类型(结果也具有此类型)
  • 因为foldr,这两个参数可能有不同的类型(结果与第二个参数的类型相同)

你的类型是insert什么?


Dan*_*ner 10

我喜欢这里给出的基于类型的答案,但我也想提供一个可操作的答案,解释为什么我们不希望这样做.让我们从源头foldr1开始:

foldr1          :: (a -> a -> a) -> [a] -> a
foldr1 _ [x]    = x
foldr1 f (x:xs) = f x (foldr1 f xs)
Run Code Online (Sandbox Code Playgroud)

现在,让我们尝试运行您的程序.

foldr1 insert [1,19,-2,7,43]
= { list syntax }
foldr1 insert (1:[19,-2,7,43])
= { definition of foldr1 }
insert 1 (foldr1 insert [19,-2,7,43])
= { three copies of the above two steps }
insert 1 (insert 19 (insert (-2) (insert 7 (foldr1 insert [43]))))
= { definition of foldr1 }
insert 1 (insert 19 (insert (-2) (insert 7 43)))
Run Code Online (Sandbox Code Playgroud)

...哎呦!这insert 7 43永远不会奏效.=)


Hau*_*eth 1

因为foldr1正在尝试这样做:

insert 43 -7
Run Code Online (Sandbox Code Playgroud)

这将会失败。