我正在完成“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
我无法弄清楚为什么会出现这种类型错误。我猜测编译器根据x
(Num
)的类型推断出z
(Char
)的类型,但我无法看到它在哪里绘制连接,因为const
或f
不需要它的两个参数是相同的类型。
有什么想法吗?
答案 0 :(得分:2)
好的看看foldr :: (a -> b -> b) -> b -> [a] -> b
从右边开始,您显然必须a
成为Num
和Enum
的某个实例(因为您使用[1..5]
)
接下来,您传递'a'
,以便b ~ Char
最后你有const
的功能 - 而const是const :: a -> b -> a
- 请注意你现在必须拥有a ~ b
,因为你统一了
a -> b -> b
a -> b -> a
^^^^^
但这当然意味着'a'
必须是Num
的{{1}}实例的值,而Char
不是......有你的错误(它抱怨1,因为从左边开始,这是问题变得明显的地方)
foldl
有foldl :: (b -> a -> b) -> b -> [a] -> b
所以现在你再次a
Num
的一些实例,b
必须再次Char
但现在const
恰好适合(只需切换{{}常量类型中的1}}和b
答案 1 :(得分:1)
foldl
和foldr
使用不同的参数顺序调用f
。这是foldr
次来电const x 'a'
,但foldl
来电const 'a' x
。后者的结果是' a',这很好,但后者的结果是x
,这是错误的,因为x
是Int
并且结果应该与累加器(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]
统一起来。类型Char
是Enum
类的实例,但不是Num
,这就是您收到此错误消息的原因。
答案 3 :(得分:1)
正如其他人所说,foldl
和foldr
中的参数顺序不同。请改用flip const
:
> foldr (flip const) 'a' [1..5]
'a'