2011-11-06 98 views
2

我想在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' 

这可能是因为我没有写逻辑正确,虽然我认为我确实..
想法?

回答

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 s。这类问题的模因是:“需要更多fromIntegral”。

(getAvg x > fromIntegral y) 
+0

可能是我见过的约哈斯克尔,感谢最全面的信息。 – Asaf

3

您的代码有两个错误。

  1. 尽管在代码类型签名声明smallerThanAVG x计算结果为Integer,其代码map ... x,这清楚地计算结果为列表,而不是一个单一的Integer
  2. 在代码getAVG x > y中,您将DoubleInteger进行比较。在Haskell中,只能比较同一类型的两个值。因此,您必须使用fromIntegral(或fromInteger)将Integer转换为Double。 (这实际上是什么导致了问题中的错误消息,但你必须习惯它来弄清楚。)

有几种方法可以修复上面的项目1,我不会写出它们(因为这样做会带走所有的乐趣)。但是,如果我没有弄错,你所瞄准的代码看起来像是计算比平均值小,更小的元素数量,尽管你在代码之前写了什么。

造型提示:

  • 你在你的代码中的许多多余的括号。例如,您不必在Haskell中的if表达式中加上条件(与C或Java中的if语句不同)。如果你想享受Haskell,你应该学习Haskell的风格,而不是Haskell。
  • 您可以在代码中调用代表列表“x”的变量。通常使用变量名称如xs来表示列表。
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] 
+0

(1)'fromIntegral'是多余的;它将在代码中将“Int”转换为“Int”。 (2)在这段代码中我不会使用变量'sum''。 (3)问题中的任务是计算大于平均数的元素数量,因此您正在解决稍微不同的问题。 –

+0

感谢您的建议! –