use*_*706 1 haskell compiler-errors typechecking
以下编译没有警告或错误.
factors n = [x | x<-[1..n], n `mod` x == 0]
perfects n = [x | x <- [1..n], x == sum (factors (init x))]
main = putStrLn "hello"
Run Code Online (Sandbox Code Playgroud)
即使我犯了错误.
perfects n = [x | x <- [1..n], x == sum (factors (init x))] -- incorrect
perfects n = [x | x <- [1..n], x == sum (init (factors x))] -- should have been
Run Code Online (Sandbox Code Playgroud)
静态类型检查在哪里进行救援?
我认为应该抓住错误的原因是:
factor显然期望一个Integral因为它的参数使用mod,而init返回aListx从绘制List的Integers,并init预计一Listaug*_*tss 18
如果你看一下ghc推断出来的类型,你可以看到
perfects :: forall a. (Eq a, Integral [a]) => [a] -> [[a]]
Run Code Online (Sandbox Code Playgroud)
所以如果你有一个实例让列表在课堂上Integral就可以了.并且ghc不知道那不是你想要的.
如果您打开了预期的类型签名perfects,或者您perfects按照预期的方式使用(更改main为print (perfects 42)),则会出现错误.
编辑这使你的代码做一些事情(荒谬):
module Main where
factors n = [x | x<-[1..n], n `mod` x == 0]
perfects n = [x | x <- [1..n], x == sum (factors (init x))]
instance Num [a]
instance Integral a => Integral [a]
instance Real a => Real [a]
instance Enum [a] where
enumFromTo _ _ = []
main = print (perfects 5)
Run Code Online (Sandbox Code Playgroud)
所以你写的可能是你想要的.这就是为什么总是编写类型签名是好的,这样编译器就可以看到你的想法了.或者至少,您应该检查推断类型是否符合您的意图.
奥古斯都说了什么,但我会补充一些想法.
这里的问题(没问题!)是Haskell做出权衡:更具灵活性,代价是具体的错误报告.由于Haskell只允许更多的东西,因此在很多情况下,与更主流的语言相比,它要么无法报告错误,要么报告的错误比其他语言报告的更抽象.
例如,假设您打算输入1 + 2,但是您需要输入并输入1 0 2.以下是Python的响应方式:
Python 2.7.2 (default, Oct 11 2012, 20:14:37)
[GCC 4.2.1 Compatible Apple Clang 4.0 (tags/Apple/clang-418.0.60)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> 1 0 2
File "<stdin>", line 1
1 0 2
^
SyntaxError: invalid syntax
Run Code Online (Sandbox Code Playgroud)
简单:"你打错了." 现在哈斯克尔:
GHCi, version 7.6.3: http://www.haskell.org/ghc/ :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
Prelude> 1 0 2
<interactive>:2:1:
No instance for (Num (a0 -> a1 -> t0)) arising from the literal `1'
Possible fix:
add an instance declaration for (Num (a0 -> a1 -> t0))
In the expression: 1
In the expression: 1 0 2
In an equation for `it': it = 1 0 2
<interactive>:2:3:
No instance for (Num a0) arising from the literal `0'
The type variable `a0' is ambiguous
Possible fix: add a type signature that fixes these type variable(s)
Note: there are several potential instances:
instance Num Double -- Defined in `GHC.Float'
instance Num Float -- Defined in `GHC.Float'
instance Integral a => Num (GHC.Real.Ratio a)
-- Defined in `GHC.Real'
...plus three others
In the first argument of `1', namely `0'
In the expression: 1 0 2
In an equation for `it': it = 1 0 2
<interactive>:2:5:
No instance for (Num a1) arising from the literal `2'
The type variable `a1' is ambiguous
Possible fix: add a type signature that fixes these type variable(s)
Note: there are several potential instances:
instance Num Double -- Defined in `GHC.Float'
instance Num Float -- Defined in `GHC.Float'
instance Integral a => Num (GHC.Real.Ratio a)
-- Defined in `GHC.Real'
...plus three others
In the second argument of `1', namely `2'
In the expression: 1 0 2
In an equation for `it': it = 1 0 2
Run Code Online (Sandbox Code Playgroud)
在Python中,1 0 2是语法错误.在Haskell中,1 0 2意味着将函数1应用于参数0和2.Haskell的错误信息不是"你不能那样做",而是"你没有告诉我如何将数字强制转换为双参数函数"(没有实例Num (a0 -> a1 -> t0)).
在你的情况下,你设法编写了Haskell知道如何解释的东西,但意味着与你的意思有很大不同.作为程序员,在这里做的最好的事情是使用描述你的意图的顶级类型声明,然后编译器可以检查这些.
最后注意事项:请记住,您可以在Haskell中执行此操作:
-- | Treat lists of numbers as numbers. Example:
--
-- >>> [1..3] * [2..5]
-- [2,3,4,5,4,6,8,10,6,9,12,15]
--
instance Num a => Num [a] where
xs + ys = [x + y | x <- xs, y <- ys]
xs * ys = [x * y | x <- xs, y <- ys]
xs - ys = [x - y | x <- xs, y <- ys]
negate xs = map negate xs
abs xs = map abs xs
signum xs = map signum xs
fromInteger x = [fromInteger x]
-- | Treat functions as numbers if they return numbers. The functions
-- must have the same argument type. Example:
--
-- >>> 1 0 2
-- 1
instance Num a => Num (r -> a) where
f + g = \r -> f r + g r
f * g = \r -> f r * g r
f - g = \r -> f r - g r
negate f = negate . f
abs f = abs . f
signum f = signum . f
fromInteger x = const (fromInteger x)
Run Code Online (Sandbox Code Playgroud)
同样的事情可以在Integral课堂上完成.