2012-03-10 105 views
3

我寫了一個函數,(應該)採取布爾的無限列表和計算時真亦假值在第一n個元素的比例:型鑄造在Haskell,分數和Int

prob n list = foldr (+) 0 (map boolToInt (take n list))/n 
    where boolToInt b 
     | b == True = 1 
     | otherwise = 0 

不幸這不是工作:

No instance for (Fractional Int) 
    arising from a use of `/' 
Possible fix: add an instance declaration for (Fractional Int) 
In the expression: foldr (+) 0 (map boolToInt (take n list))/n 
In an equation for `prob': 
    prob n list 
     = foldr (+) 0 (map boolToInt (take n list))/n 
     where 
      boolToInt b 
      | b == True = 1 
      | otherwise = 0 
Failed, modules loaded: none. 

我試圖做一個轉換,但不工作之一:

prob n list = foldr (+) 0 (map boolToInt (take (fromIntegral (toInteger n)) list))/n 
    where boolToInt b 
     | b == True = 1 
     | otherwise = 0 

它的編制,但只要我嘗試調用的函數,我得到一個錯誤:

*Main> prob 50 toCoin1 
<interactive>:1:6: 
Ambiguous type variable `a0' in the constraints: 
    (Num a0) arising from the literal `50' at <interactive>:1:6-7 
    (Integral a0) arising from a use of `prob' at <interactive>:1:1-4 
    (Fractional a0) arising from a use of `prob' at <interactive>:1:1-4 
Probable fix: add a type signature that fixes these type variable(s) 
In the first argument of `prob', namely `50' 
In the expression: prob 50 toCoin1 
In an equation for `it': it = prob 50 toCoin1 

有什麼建議?

回答

11

您正在轉換錯誤的地方。嘗試在整個foldrn附近附上fromRational

prob n list = fromIntegral count/fromIntegral n 
    where count = foldr (+) 0 (map boolToInt (take n list)) 
      boolToInt b 
      | b == True = 1 
      | otherwise = 0 

哦,你boolToInt功能是相同的fromEnum專門到Bool秒。

prob n list = fromIntegral count/fromIntegral n 
    where count = foldr (+) 0 (map fromEnum (take n list)) 

與你試圖做什麼的根本問題是你強加給第一個參數prob相互衝突的要求。您使用toInteger約束nIntegral,但其在/中的使用要求它是Fractional,並且沒有類型是IntegralFractional

+0

這不適合我,應'fromRational'是'fromIntegral'? – huon 2012-03-10 02:57:19

+0

@dbaupp:呃,是的,它應該。猜猜我不應該在網絡瀏覽器中編碼。 – 2012-03-10 03:03:06

+0

@dbaupp:如果您爲'prob'編寫頂級類型聲明,例如'prob :: Int - > [Bool] - > Float',那麼你會得到一個更好的錯誤信息。 – 2012-03-10 03:05:06

0

BoolEnum的一個實例,所以boolToInt已由fromEnum提供。此外,foldrsum,因此整個功能可以簡化爲:

prob n list = (fromIntegral . sum . map fromEnum . take n) list/fromIntegral n 

我們能抽象出用於計算平均值(儘管這將需要確定列表的長度的代碼,我們已經知道):

mean xs = (fromIntegral . sum) xs/(fromIntegral . length) xs 

prob n = mean . map fromEnum . take n 
+0

平均函數是一個不好的消費者:它在兩個點使用xs,所以它將保留xs的頭部,直到總和達到最後一個元素。整個列表必須在內存中......通常的迴應是在一次遍歷中累加和和長度:'foldl'(\(!sum,!len)x - >(sum + x,len + 1))(0,0)'。 – Jedai 2012-03-10 14:13:48

+0

不錯!優化器無法爲你做到這一點太糟糕了...... – pat 2012-03-10 17:06:20

+0

很難發現這種情況,並且確定正確的方法來做到這一點(有懶惰的擔憂也要考慮,你不會希望爲所有操作員完成此操作...)。另一方面,如果你開始編寫並行代碼,即使最初的平均值並行化也可能是一個好消費者(因爲兩個遍歷都可以同時發生)。 – Jedai 2012-03-10 17:54:53