0

我正在尝试使用以下函数计算谐波级数。但是有一个类型错误,不太清楚这意味着什么?另一个问题,为什么 [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]    
4

3 回答 3

7

该错误告诉您您的代码类型不正确,因此没有意义。

你的功能:

sumHR = foldr (+) 0 (\x -> map (1/) [1..x])

考虑:

Prelude> :t foldr
foldr :: (a -> b -> b) -> b -> [a] -> b

因此,要做到这一点,(+)第一个参数是第一个参数,并且类型必须统一(a -> b -> bNum a => a -> a -> a统一到Num a => a -> a -> a)。

第二个参数是类型变量b,我们已经知道它必须是Num a => a。这很好,您已经提供0了第二个参数。

第三个参数必须与 type 一致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])
于 2013-05-14T01:54:48.833 回答
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

于 2013-05-14T01:54:09.907 回答
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..] ]
于 2013-05-14T08:03:57.523 回答