SICP练习中的Haskell数值类型层次结构

时间:2010-08-04 16:19:58

标签: haskell types type-conversion

我最近一直在学习Haskell,正在和一位正在通过SICP工作的朋友交谈。我们很想比较Common Lisp和Scheme,所以我决定尝试将练习1.29翻译成Haskell。

本练习使用函数sigma,它表示数学求和函数Sigma。此函数采用函数f应用于每个术语,下限,应用于每个术语以获得下一个术语的函数和上限。它返回应用于每个术语的f的总和。

simpsonIntegral应该使用Simpson规则使用“精度”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 个答案:

答案 0 :(得分:6)

fromIntegral :: (Integral a, Num b) => a -> b

r = fromIntegral i

答案 1 :(得分:3)

跟进Justice的回答:如果您对fromIntegral的放置位置感到好奇,请编译以下内容:

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

答案 2 :(得分:1)

问题是函数“odd”期望它的参数是Integral类型。编译器然后推断您的变量“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