2010-08-04 88 views
5

我最近一直在學習Haskell,並正在與正在通過SICP工作的朋友交談。我們很好奇比較Common Lisp和Scheme,所以我決定將練習1.29轉換成Haskell。SICP練習中的Haskell數字類型層次結構

本練習使用表示數學求和函數Sigma的函數sigma。這個函數採用一個函數f來應用於每個項,一個下界,一個應用於每個項以得到下一項的函數,以及一個上界。它返回應用於每個術語的f的總和。

simpsonIntegral應該使用辛普森規則來使用「精確度」n近似函數f在範圍[a,b]上的積分。我無法使此功能正常工作,因爲似乎有些事情我不明白所涉及的類型。

此代碼將使用ghc版本6.12.1進行編譯,但simpsonIntegral將被賦予一個類型上下文(Integral a,Fractional a),它沒有任何意義,只要您調用該函數就會激活該函數。我一直在努力工作,但是我所做的顯然是一種黑客攻擊,所以我想在這裏問一下,這將如何處理。

人們如何習慣性地處理h中所需的積分 - >分數/實數轉換?我讀了很多東西,但沒有看到任何明顯和乾淨的東西。

sigma :: (Ord a, Num b) => (a -> b) -> a -> (a -> a) -> a -> b 
sigma f a next b = iter a 0 
    where 
    iter current acc | current > b = acc 
        | otherwise = iter (next current) (acc + f current) 

simpsonIntegral f a b n = 1.0 * (h/3) * (sigma simTerm 0 (1+) n) 
    where 
    h = (b - a)/n 
    simTerm k = (yk k) * term 
     where 
     yk k = f (a + h * k) 
     term = 
      case k of 
      0 -> 1 
      1 -> 1 
      otherwise -> if odd k then 4 else 2 

回答

3

要跟進司法的答案:如果您想了解哪裏放fromIntegral S,以下編譯:

simpsonIntegral :: (Integral a, Fractional b) => (b -> b) -> a -> a -> a -> b 
simpsonIntegral f a b n = 1.0 * (h/3) * (sigma simTerm 0 (1+) n) 
    where 
    h = fromIntegral (b - a)/fromIntegral n 
    simTerm k = (yk k) * term 
     where 
     yk k = f (fromIntegral a + h * fromIntegral k) 
     term = 
      case k of 
      0 -> 1 
      1 -> 1 
      otherwise -> if odd k then 4 else 2 

而且似乎工作:

*Main> simpsonIntegral (^3) 0 1 100 
0.2533333233333334 
*Main> simpsonIntegral (^3) 0 1 1000 
0.2503333333323334 
6
fromIntegral :: (Integral a, Num b) => a -> b 

r = fromIntegral i 
+0

關於fromIntegral的問題。我正在嘗試這個,但沒有在每個特拉維斯的答案的正確位置,我認爲這是行不通的,因爲根據這個http://www.haskell.org/tutorial/numbers.html數字不提供一個劃分運算符。是從返回類型和ghc的積分多態性推斷我想要一個小數返回類型? – asm 2010-08-07 11:11:52

+0

是的,'fromIntegral'在其返回類型'b'中是多態的,因爲'b'(返回類型)允許是任何數據類型,它是'Num'類型類的成員。雖然'Num'類型不提供除法,但屬於該類型成員的某些數據類型確實提供了除法,例如'Double'。 – yfeldblum 2010-08-07 13:54:12

1

問題是函數「奇怪」期望它的參數是一個積分類型。然後編譯器會推斷出你的變量「k」是Integral類型的。但通過使用「/」操作,編譯器推斷「k」也是Fractional類型。該解決方案可爲轉換「K」作爲簡單的整數,其中它真正需要的:

if odd (round k) then 4 else 2 

如果您想了解更多關於Haskell的數字轉換,檢查Converting_numbers

作爲一個側面說明,這裏的另一個寫西格瑪函數的方法:

sigma f a next b = sum $ map f $ takeWhile (<= b) $ iterate next a