数字划分的类型声明

时间:2014-08-23 17:26:39

标签: haskell types sicp

我尝试了所有可能的类型声明,但我无法编译这段代码。诀窍是处理分裂的类型。我尝试了Num aFractional aFloat a等。

cube x = x * x * x

sum' term a next b =
    if a > b
    then 0
    else term a + sum' term (next a) next b

integral f a b n = (h / 3) * (sum' term 0 succ n)  where
    h = (b - a) / n
    y k = f $ a + (k * h)
    term k
        | k == 0 || k == n  = y k
        | odd  k            = 4 * y k
        | even k            = 2 * y k

main = do
    print $ integral cube 0 1 100      -- 0.25
    print $ (\x -> 3 * x * x) 1 3 100  -- 26

我通过删除(/)功能来隔离问题。此代码在没有任何类型声明的情况下编译:

cube x = x * x * x

sum' term a next b =
    if a > b
    then 0
    else term a + sum' term (next a) next b

integral f a b n = (sum' term 0 succ n)  where
    h = (b - a)
    y k = f $ a + (k * h)
    term k
        | k == 0 || k == n  = y k
        | odd  k            = 4 * y k
        | even k            = 2 * y k

main = do
    print $ integral cube 0 1 100

另一个问题是如何调试这样的案例? Haskell的错误消息并没有多大帮助,很难理解The type variable a0 is ambiguousCould not deduce (a1 ~ a)之类的内容。

P上。 S.它的前任。 1.29来自SICP。

更新

最后的答案是:

cube :: Num a => a -> a
cube x = x * x * x

sum' :: (Int -> Double) -> Int -> (Int -> Int) -> Int -> Double
sum' term a next b =
    if a > b
    then 0
    else term a + sum' term (next a) next b

integral :: (Double -> Double) -> Double -> Double -> Int -> Double
integral f a b n = (h / 3) * sum' term 0 (+1) n  where
    h = (b - a) / n'  where n' = fromIntegral n
    y k = f $ a + (k * h)
    term k
        | k == 0 || k == n  = y k'
        | odd  k            = 4 * y k'
        | even k            = 2 * y k'
        where k' = fromIntegral k

main = do
    print $ integral cube 0 1 100               -- 0.25
    print $ integral cube 0 1 1000              -- 0.25
    print $ integral (\x -> 3 * x * x) 1 3 100  -- 26

1 个答案:

答案 0 :(得分:6)

/仅用于Fractional实例的类型,Integral类型使用quot。您可以使用反引号将quot用作中缀运算符:

h = (b - a) `quot` n

两者的类型是

(/) :: Fractional a => a -> a -> a
quot :: Integral a => a -> a -> a

没有类型是FractionalIntegral的实例,这就是为什么类型签名都不起作用的原因。不幸的是,GHC并不知道类型不可能是两个类的实例,因此错误消息不是很直观。您已经习惯了GHC错误消息的样式,并且它们提供的细节有很多帮助。

另外,正如评论中所建议的那样,我完全同意所有顶级定义都应该给出类型签名(包括main)。它使错误消息很多更容易阅读。

编辑:基于下面的评论,看起来你想要的是更像这样的东西(类型签名方式)

cube :: Num a => a -> a

sum' :: (Int -> Double) -> Int -> (Int -> Int) -> Int -> Double

integral :: (Double -> Double) -> Double -> Double -> Int -> Double

您需要使用fromIntegralIntDouble中将h转换为k。但是,对于这些类型的签名,类型错误至少应该更具可读性。