Haskell foldr导致类型错误,而foldl则不会

时间:2016-03-16 22:05:08

标签: haskell lazy-evaluation fold

我正在完成“Haskell Programming From First Principles”。在“折叠列表”一章中,练习5f,

当我评估时

foldr const 'a' [1..5]

我得到了

  

没有(Num Char)的实例来自文字“1”

然而,

foldl const 'a' [1..5]

我得到'a'

我知道折叠是懒惰的,foldr不会遍历脊椎而foldl会这样做。但即使看看foldr和foldl的定义,

foldr f z []     = z 
foldr f z (x:xs) = f x (foldr f z xs) 

foldl f z []     = z                  
foldl f z (x:xs) = foldl f (f z x) xs

我无法弄清楚为什么会出现这种类型错误。我猜测编译器根据xNum)的类型推断出zChar)的类型,但我无法看到它在哪里绘制连接,因为constf不需要它的两个参数是相同的类型。

有什么想法吗?

4 个答案:

答案 0 :(得分:2)

好的看看foldr :: (a -> b -> b) -> b -> [a] -> b

的类型

从右边开始,您显然必须a成为NumEnum的某个实例(因为您使用[1..5]

接下来,您传递'a',以便b ~ Char

最后你有const的功能 - 而const是const :: a -> b -> a - 请注意你现在必须拥有a ~ b,因为你统一了

a -> b -> b
a -> b -> a
        ^^^^^

但这当然意味着'a'必须是Num的{​​{1}}实例的值,而Char不是......有你的错误(它抱怨1,因为从左边开始,这是问题变得明显的地方)

另一方的

foldlfoldl :: (b -> a -> b) -> b -> [a] -> b

所以现在你再次a Num的一些实例,b必须再次Char但现在const恰好适合(只需切换{{}常量类型中的1}}和b

答案 1 :(得分:1)

foldlfoldr使用不同的参数顺序调用f。这是foldr次来电const x 'a',但foldl来电const 'a' x。后者的结果是' a',这很好,但后者的结果是x,这是错误的,因为xInt并且结果应该与累加器(Char)具有相同的类型。

答案 2 :(得分:1)

这是打字问题。 foldl的类型是

foldl :: Foldable t => (b -> a -> b) -> b -> t a -> b    

foldr类型为:

foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b

当您将foldr应用于const时,您会获得:

foldr const :: Foldable t => b -> t b -> b

接下来,你提供'a'参数,你得到

(foldr const 'a') :: Foldable t => t Char -> Char

因此,当您将[1..5]作为参数传递时,它会尝试将t Char(Enum a, Num a) => [a]统一起来。类型CharEnum类的实例,但不是Num,这就是您收到此错误消息的原因。

答案 3 :(得分:1)

正如其他人所说,foldlfoldr中的参数顺序不同。请改用flip const

> foldr (flip const) 'a' [1..5]
'a'