sur*_*nov 1 haskell types sicp
我尝试了所有可能的类型声明,但我不能使这个代码甚至编译.诀窍是处理分裂的类型.我试过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
Run Code Online (Sandbox Code Playgroud)
我通过删除(/)功能来隔离问题.此代码在没有任何类型声明的情况下编译:
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
Run Code Online (Sandbox Code Playgroud)
另一个问题是如何调试这样的案例?Haskell的错误消息没有多大帮助,有点难以理解The type variable a0 is ambiguous或类似的东西Could not deduce (a1 ~ a).
PS它是前.来自SICP的1.29.
更新
最后的答案是:
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
Run Code Online (Sandbox Code Playgroud)
/仅用于那些实例的类型Fractional,对于Integral类型使用quot.您可以使用quot反引号作为中缀运算符:
h = (b - a) `quot` n
Run Code Online (Sandbox Code Playgroud)
两者的类型是
(/) :: Fractional a => a -> a -> a
quot :: Integral a => a -> a -> a
Run Code Online (Sandbox Code Playgroud)
有没有类型都是实例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
Run Code Online (Sandbox Code Playgroud)
您将需要使用fromIntegral转换Int为Doublein h和in k.但是,对于这些类型的签名,类型错误应至少更具可读性.