我正在尝试在Haskell中编写一个程序
获取一个列表(整数)并打印出大于列表平均值的元素数量
到目前为止我试过
getAVG::[Integer]->Double
getAVG x = (fromIntegral (sum x)) / (fromIntegral (length x))
smallerThanAVG:: [Integer]->Integer
smallerThanAVG x = (map (\y -> (if (getAVG x > y) then 1 else 0)) x)
出于某种原因,我收到此错误
Couldn't match expected type `Double'
against inferred type `Integer'
Expected type: [Double]
Inferred type: [Integer]
In the second argument of `map', namely `x'
可能我没有正确地写出逻辑,虽然我认为我做了..
想法?
答案 0 :(得分:6)
这些错误是最好的,因为它们可以找出造成类型错误的位置。
所以让我们做一些手动类型推断。让我们考虑一下表达式:
map (\y -> (if (getAvg x > y) then 1 else 0)) x
我们知道一些限制因素:
map :: (a -> b) -> [a] -> [b] -- from definition
(>) :: Num a => a -> a -> Bool -- from definition
getAvg :: [Integer] -> Double -- from type declaration
1, 0 :: Num a => a -- that's how Haskell works
x :: [Integer] -- from type declaration of smallerThanAVG
现在让我们看看更大的表达式。
expr1 = getAvg x
expr2 = (expr1 > y)
expr3 = (if expr2 then 1 else 0)
expr4 = (\y -> expr3)
expr5 = map expr4 x
现在让我们倒退吧。 expr5
与smallerThanAVG
的RHS相同,这意味着它与您声明的结果类型相同。
expr5 :: Integer -- wrong
但是,这与我们的其他约束不匹配:对于某些map
,[b]
的结果必须为b
。 Integer
肯定是不是一个列表(尽管如果你变得滑稽,它可能被强制转换为一个位列表)。你可能想要列出sum
。
expr6 = sum expr5
sum :: Num a => [a] -> a
现在让我们继续前进。
expr1 :: Double -- result type of getAvg
y :: Double -- (>) in expr2 requires both inputs to have the same type
expr4 :: (Integer -> [a]) -- because for `map foo xs` (expr5)
-- where xs :: [a], foo must accept input a
y :: Integer -- y must have the input type of expr4
冲突就在于:y
不能同时是Double
和Integer
。我可以等同地重申:x
不能同时是[Double]
和[Integer]
,这正是编译器所说的。所以tl; dr,踢球者(>)
没有比较不同类型的Num
。这类问题的模因是:“需要更多fromIntegral
”。
(getAvg x > fromIntegral y)
答案 1 :(得分:3)
您的代码有两个错误。
smallerThanAVG x
的评估结果为Integer
,但其代码为map ... x
,明确评估为列表而不是单个Integer
getAVG x > y
中,您要将Double
与Integer
进行比较。在Haskell中,您只能比较两个相同类型的值。因此,您必须使用fromIntegral
(或fromInteger
)将Integer
转换为Double
。 (这实质上是导致问题中出现错误信息的原因,但你必须习惯它来解决它。)有几种方法可以修复上面的第1项,我不会写它们(因为这样做会带走所有的乐趣)。但是,如果我没有弄错的话,你所针对的代码似乎计算小于的元素的数量,而不是你在代码之前写的东西。
造型提示:
if
表达式中括起条件(与C或Java中的if
语句不同)。如果你想享受Haskell,你应该学习Haskell,而不是正常工作的Haskell。x
”的变量。通常使用诸如xs
之类的变量名来表示列表。答案 2 :(得分:2)
其他人已经很好地解释了这些错误。
我还在学习Haskell,但我想提供此功能的替代版本:
greaterThanAvg :: [Int] -> [Int]
greaterThanAvg xs = filter (>avg) xs
where avg = sum xs `div` length xs
cnt = length $ greaterThanAvg [1,2,3,4,5]