我尝试了所有可能的类型声明,但我无法编译这段代码。诀窍是处理分裂的类型。我尝试了Num a
,Fractional a
,Float 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 ambiguous
或Could 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
答案 0 :(得分:6)
/
仅用于Fractional
实例的类型,Integral
类型使用quot
。您可以使用反引号将quot
用作中缀运算符:
h = (b - a) `quot` n
两者的类型是
(/) :: Fractional a => a -> a -> a
quot :: Integral a => a -> a -> a
没有类型是Fractional
和Integral
的实例,这就是为什么类型签名都不起作用的原因。不幸的是,GHC并不知道类型不可能是两个类的实例,因此错误消息不是很直观。您已经习惯了GHC错误消息的样式,并且它们提供的细节有很多帮助。
另外,正如评论中所建议的那样,我完全同意所有顶级定义都应该给出类型签名(包括main
)。它使错误消息很多更容易阅读。
编辑:基于下面的评论,看起来你想要的是更像这样的东西(类型签名方式)
cube :: Num a => a -> a
sum' :: (Int -> Double) -> Int -> (Int -> Int) -> Int -> Double
integral :: (Double -> Double) -> Double -> Double -> Int -> Double
您需要使用fromIntegral
在Int
和Double
中将h
转换为k
。但是,对于这些类型的签名,类型错误至少应该更具可读性。