2011-11-06 103 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

感謝您的建議! –