我正在尝试在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)
Run Code Online (Sandbox Code Playgroud)
出于某种原因,我收到了这个错误
Couldn't match expected type `Double'
against inferred type `Integer'
Expected type: [Double]
Inferred type: [Integer]
In the second argument of `map', namely `x'
Run Code Online (Sandbox Code Playgroud)
可能是我没有正确地写出逻辑,虽然我认为我做了..
想法?
这些错误是最好的,因为它们可以确定您发生类型错误的位置.
那么让我们做一些手动类型推断.让我们考虑一下这个表达式:
map (\y -> (if (getAvg x > y) then 1 else 0)) x
Run Code Online (Sandbox Code Playgroud)
我们知道一些限制:
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
Run Code Online (Sandbox Code Playgroud)
现在让我们看看更大的表达式.
expr1 = getAvg x
expr2 = (expr1 > y)
expr3 = (if expr2 then 1 else 0)
expr4 = (\y -> expr3)
expr5 = map expr4 x
Run Code Online (Sandbox Code Playgroud)
现在让我们倒退吧.expr5与RHS相同smallerThanAVG,这意味着它与您声明的结果类型相同.
expr5 :: Integer -- wrong
Run Code Online (Sandbox Code Playgroud)
但是,这与我们的其他约束不匹配:结果map必须是[b]某些b.Integer绝对不是一个列表(虽然如果你变得滑稽,它可能被强制成一个列表).你可能意味着sum那个列表.
expr6 = sum expr5
sum :: Num a => [a] -> a
Run Code Online (Sandbox Code Playgroud)
现在让我们继续前进吧.
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
Run Code Online (Sandbox Code Playgroud)
这里存在冲突:y不能既是一个Double和Integer.我能等效重申这是:x不能既[Double]和[Integer],这是编译器说.所以tl; dr,踢球者(>)不会比较不同类型的Nums.这类问题的模因是:"需要更多fromIntegral".
(getAvg x > fromIntegral y)
Run Code Online (Sandbox Code Playgroud)