创建一个函数来汇总haskell中的奇数平方

时间:2014-03-17 17:44:47

标签: haskell

 sumoddsquare' :: (Num a) => [a] -> a
 sumoddsquare' = sum [x^2 | x <- [1..5], odd x]

我想要的输出是35

我得到的语法错误是

Couldn't match expected type `[a] -> a'
    with actual type `[Integer]'
    In the expression: [x ^ 2 | x <- [1 .. 9999], odd x]
    In an equation for sumoddsquare':
        sumoddsquare' = [x ^ 2 | x <- [1 .. 9999], odd x]

你能解释一下这个语法错误,并为这个问题提供解决方案吗?

1 个答案:

答案 0 :(得分:3)

您已sumoddsquare'类型为Num a => [a] -> a,但您已停用任何参数。也许你的意思是

sumoddsquare' xs = sum [x^2 | x <- xs, odd x]

虽然此处Num约束不充分,但请检查^2odd的类型以确定您应该使用的内容。 (下面的剧透)


根据错误消息判断,您实际上已将代码中的sumoddsquare'定义为

sumoddsquare' :: [a] -> a
sumoddsquare' = [x^2 | x <- [1..9999], odd x]

而不是你上面发布的内容。现在,您已明确地将类型[a] -> a赋予sumoddsquares',编译器将其视为事实,但随后它会看到定义。您没有在定义中明确定义参数,因此编译器认为您是以无点样式定义函数。当它看到=的右侧时,会因为[x^2 | x <- [1..9999], odd x]的类型为[Integer]而感到困惑,但它已经接受sumoddsquares'具有类型{[a] -> a的事实{1}}。它不知道如何调和它,所以它会引发你看到的错误。


通常可以通过注释掉显式类型签名来找到这些类型的错误消息的来源。如果它然后编译,你可以通过

检查GHCi中的类型
> :load sumoddsquare_no_type_sig.hs
> :type sumoddsquare'
[Integer]

这会告诉你sumoddsquare'不是一个功能。但是,你希望它是一个函数,那么你如何解决这个问题呢?首先,看一下定义。您的所有参数都是明确声明的吗?如果不是,请添加它们。

-- sumoddsquare' :: Num a => [a] -> a
sumoddsquare' xs = [x^2 | x <- [1..9999], odd x]

然后你看

> :reload
> :type sumoddsquare'
[a] -> [Integer]

这至少是一个函数,但我们如何从一般类型[a][Integer]?由于我们目前对a一无所知,因此该函数不能完全取决于第一个参数!然后我们可以查看我们的定义以找到列表的位置

-- sumoddsquare' :: Num a => [a] -> a
sumoddsquare' xs = [x^2 | x <- xs, odd x]
--                             ^--- This is the only place I saw a list used

然后

> :reload
> :type sumoddsquare'
Integral a => [a] -> [a]

那更接近了!我们发现输入已限制为Integral,我们返回的通用类型不仅仅是[Integer]。这告诉我们首先需要在Num aIntegral a的类型签名中修复约束。最后一个难题是弄清楚如何将Integral a => [a]转换为Integral a => a。我们想要求和,所以现在我们看到我们在列表理解之前省略了sum函数

-- sumoddsquare' :: Integral a => [a] -> a
sumoddsquare' xs = sum [x^2 | x <- xs, odd x]

最后

> :reload
> :type sumoddsquare'
Integral a => [a] -> a

我们有一个符合我们想要的类型。我们现在可以在源代码中取消注释类型签名。


作为奖励,这个问题可以通过更高阶函数完全解决

sumoddsquares' xs = sum $ map (^2) $ filter odd $ xs
-- or point free as
-- sumoddsquares' = sum . map (^2) . filter odd

事实上,所有列表推导只是mapfilterconcat s的语法糖。这两段代码在编译后最终基本相同。