列表中的元素数量大于平均值

时间:2011-11-06 20:04:20

标签: haskell

我正在尝试在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'

可能我没有正确地写出逻辑,虽然我认为我做了..
想法?

3 个答案:

答案 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

现在让我们倒退吧。 expr5smallerThanAVG的RHS相同,这意味着它与您声明的结果类型相同。

expr5 :: Integer -- wrong

但是,这与我们的其他约束不匹配:对于某些map[b]的结果必须为bInteger肯定是不是一个列表(尽管如果你变得滑稽,它可能被强制转换为一个位列表)。你可能想要列出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不能同时是DoubleInteger。我可以等同地重申:x不能同时是[Double][Integer],这正是编译器所说的。所以tl; dr,踢球者(>)没有比较不同类型的Num。这类问题的模因是:“需要更多fromIntegral”。

(getAvg x > fromIntegral y)

答案 1 :(得分:3)

您的代码有两个错误。

  1. 虽然代码中的类型签名声明smallerThanAVG x的评估结果为Integer,但其代码为map ... x,明确评估为列表而不是单个Integer
  2. 在代码getAVG x > y中,您要将DoubleInteger进行比较。在Haskell中,您只能比较两个相同类型的值。因此,您必须使用fromIntegral(或fromInteger)将Integer转换为Double。 (这实质上是导致问题中出现错误信息的原因,但你必须习惯它来解决它。)
  3. 有几种方法可以修复上面的第1项,我不会写它们(因为这样做会带走所有的乐趣)。但是,如果我没有弄错的话,你所针对的代码似乎计算小于的元素的数量,而不是你在代码之前写的东西。

    造型提示:

    • 您的代码中有许多多余的括号。例如,您不必在Haskell中的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]