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

SICP练习中的Haskell数字类型层次结构,haskell,types,type-conversion,Haskell,Types,Type Conversion,我最近一直在学习Haskell,并与一位通过SICP工作的朋友交谈。我们很想比较常见的Lisp和Scheme,所以我决定尝试将练习1.29翻译成Haskell 本练习使用表示数学求和函数sigma的函数sigma。该函数取一个函数f应用于每个项、一个下界、一个函数应用于每个项以获得下一个项和一个上界。它返回应用于每个项的f之和 simpsonIntegral应该使用辛普森规则来近似函数f在[a,b]范围内的积分,使用“精度”n。我很难让这个函数正常工作,因为我似乎对所涉及的类型有些不了解 这段代

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

本练习使用表示数学求和函数sigma的函数sigma。该函数取一个函数f应用于每个项、一个下界、一个函数应用于每个项以获得下一个项和一个上界。它返回应用于每个项的f之和

simpsonIntegral应该使用辛普森规则来近似函数f在[a,b]范围内的积分,使用“精度”n。我很难让这个函数正常工作,因为我似乎对所涉及的类型有些不了解

这段代码将使用ghc的6.12.1版本编译,但是SimpsonIntergral将被赋予一个类型上下文(整数a,分数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

为了跟进Justice的回答:如果您对Integral的
放在哪里感到好奇,请编译以下内容:

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

问题是函数“odd”期望它的参数是整数类型。然后,编译器推断变量“k”是Integral类型。但通过使用“/”运算,编译器推断“k”也是分数类型。解决方案可以简单到将“k”转换为真正需要的整数:

if odd (round k) then 4 else 2
如果您想了解有关Haskell中数字转换的更多信息,请选中

作为旁注,这里有另一种编写sigma函数的方法:

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

sigma f a next b=sum$map f$takeWhile(关于fromIntegral的问题。根据Travis的回答,我尝试了这个方法,但没有在正确的位置,我认为它不起作用,因为根据这个num,它没有提供除法运算符。fromIntegral在返回类型上是多态的吗?ghc推断我想要一个分数返回类型吗?是的,
fromIntegral
在其属性上是多态的返回类型
b
,其中
b
(返回类型)允许是
Num
类型类成员的任何数据类型。虽然
Num
类型类不提供除法,但属于该类型类成员的某些数据类型提供除法,例如
Double
sigma f a next b = sum $ map f $ takeWhile (<= b) $ iterate next a