我正在尝试使用下面的函数计算谐波系列。但是有一个类型错误,不太确定它是什么意思?另一个问题,为什么[5..1]会给出一个空列表?
sumHR = foldr(+)0(\ x - > map(1 /)[1..x])
错误消息:
*** Expression : foldr (+) 0 (\x -> map (1 /) (enumFromTo x 1))
*** Term : \x -> map (1 /) (enumFromTo x 1)
*** Type : b -> [b]
*** Does not match : [a]
答案 0 :(得分:7)
错误告诉您,您的代码类型不合适,因此没有意义。
你的职能:
sumHR = foldr (+) 0 (\x -> map (1/) [1..x])
考虑:
Prelude> :t foldr
foldr :: (a -> b -> b) -> b -> [a] -> b
为此,(+)
是第一个参数,类型必须统一(a -> b -> b
和Num a => a -> a -> a
统一为Num a => a -> a -> a
)。
第二个参数给出了类型变量b
,我们已经知道它必须是Num a => a
。这很好,你提供了0
作为第二个参数。
第三个参数必须与Num a => [a]
类型一致。但是,您提供了第二个参数,它是一个函数:
Prelude> :t (\x -> map (1/) [1..x])
(\x -> map (1/) [1..x]) :: (Enum b, Fractional b) => b -> [b]
除非您能够向编译器显示(Enum b, Fractional b) => b -> [b]
的类型如何与Num a => [a]
相同,否则您将被卡住。
您可能拥有以下功能:
sumHR x = foldr (+) 0 (map (1/) [1..x])
答案 1 :(得分:4)
您是否尝试无点编写?如果是,则需要使用合成运算符.
与foldr (+) 0
合并(\x -> map (1/) [1..x])
。
sumHR = foldr (+) 0 . (\x -> map (1/) [1..x])
或,完全点:
sumHR x = foldr (+) 0 (map (1/) [1..x])
(顺便说一下,为了提高效率,您需要使用foldl'
代替foldr
)
答案 2 :(得分:4)
之前的答案已经解释了如何使用您显然想要的签名修复该功能;然而,这并不是计算序列的好方法,因为对于您请求的每个元素,它必须从头开始。一个更有效的,在Haskell实际上更容易,方法是计算一个代表整个序列的惰性列表。所以,你从
开始map (1/) [1..]
(或者,可能更具可读性,[ 1/i | i<-[1..] ]
),然后执行“结果的每个元素是给定列表中所有前面元素的总和”。这称为扫描。由于在列表的整个一侧(而不仅仅是两个元素,如折叠)总是严格的,因此需要从左侧完成。你可以写
sumHR' :: Fractional x => [x]
sumHR' = scanl (+) 0 [ 1/i | i<-[1..] ]
或者,因为无限列表永远不会为空,
sumHR' = scanl1 (+) [ 1/i | i<-[1..] ]