【问题标题】:Haskell - what is wrong with this function?Haskell - 这个功能有什么问题?
【发布时间】:2013-05-14 01:44:06
【问题描述】:

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

【问题讨论】:

标签: haskell functional-programming


【解决方案1】:

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

你的功能:

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 作为第二个参数。

第三个参数必须与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])

【讨论】:

    【解决方案2】:

    你是不是想写点免费的?如果是这样,您需要使用组合运算符. 组合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

    【讨论】:

    • 而不是fold' (+) 0 为什么不是sum
    • 我也喜欢你的回答,因为它提高了点运算符!
    【解决方案3】:

    前面的答案已经解释了如何使用您显然想要的签名来修复函数;但是,这并不是计算 sequence 的真正好方法,因为对于您请求的每个元素,它都必须从头开始。一种更有效、在 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..] ]
    

    【讨论】:

      猜你喜欢
      • 2018-12-12
      • 1970-01-01
      • 1970-01-01
      • 2015-04-11
      • 1970-01-01
      • 1970-01-01
      • 2010-12-14
      • 2021-09-10
      • 2023-03-29
      相关资源
      最近更新 更多