签名不仅仅适用于文档(即使它们对于此也非常有用)。它们由编译器强制执行,这意味着通过添加签名可以使您的函数的类型比其他方式更具限制性。玩具例子:
add x y = x + y
addInt :: Int -> Int -> Int
addInt x y = x + y
*Main> :t add
add :: Num a => a -> a -> a
*Main> add 2 3
5
*Main> add 2.1 3.1
5.2
*Main> :t addInt
addInt :: Int -> Int -> Int
*Main> addInt 2 3
5
*Main> addInt 2.1 3.1 -- addInt will not accept non-Ints.
<interactive>:23:8:
No instance for (Fractional Int) arising from the literal ‘2.1’
In the first argument of ‘addInt’, namely ‘2.1’
In the expression: addInt 2.1 3.1
In an equation for ‘it’: it = addInt 2.1 3.1
除此之外,加入类型签名意味着您将得到更好的(即更容易理解)在棘手的情况下错误,因为编译器会知道你想达到的,而不是什么必须自行猜测所有事情。
在某些情况下,如果没有某些签名或其他类型注释的帮助,编译器无法确定类型。也许最简单的例子是:
readAndShow s = show (read s)
如果您尝试使用不指定任何类型的...
Foo.hs:6:17:
No instance for (Show a0) arising from a use of ‘show’
The type variable ‘a0’ is ambiguous
Note: there are several potential instances:
instance (GHC.Arr.Ix a, Show a, Show b) => Show (GHC.Arr.Array a b)
-- Defined in ‘GHC.Arr’
instance Show a => Show (Maybe a) -- Defined in ‘GHC.Show’
instance (Integral a, Show a) => Show (GHC.Real.Ratio a)
-- Defined in ‘GHC.Real’
...plus 26 others
In the expression: show (read s)
In an equation for ‘readAndShow’: readAndShow s = show (read s)
Foo.hs:6:23:
No instance for (Read a0) arising from a use of ‘read’
The type variable ‘a0’ is ambiguous
Note: there are several potential instances:
instance (GHC.Arr.Ix a, Read a, Read b) => Read (GHC.Arr.Array a b)
-- Defined in ‘GHC.Read’
instance Read a => Read (Maybe a) -- Defined in ‘GHC.Read’
instance (Integral a, Read a) => Read (GHC.Real.Ratio a)
-- Defined in ‘GHC.Read’
...plus 25 others
In the first argument of ‘show’, namely ‘(read s)’
In the expression: show (read s)
In an equation for ‘readAndShow’: readAndShow s = show (read s)
Failed, modules loaded: none.
...它不会工作。 read
将String
转换为一些类型,而show
则相反。但是,如果没有指定read s
的类型,则编译器无法确定要将String
读作哪种类型。所以,你要么需要指定中间型...
readAndShowAsInt s = show (read s :: Int)
*Main> readAndShowAsInt "2"
"2"
...还是有别的东西挑类型为您提供:
readAndAdd :: String -> Int -> Int
readAndAdd s y = read s + y
*Main> readAndAdd "2" 3
5
不完全。我相信Haskell会根据你的代码检查你的类型声明。 Python是动态输入的,不会这样做。 – Kevin
我明白了。因此,尽管在编译时确定了类型(而不必象在java/C++中那样声明类型),但显式使用类型声明还是可以避免编译错误的机会?我对haskell很陌生。 – Byte
这是我的理解,Haskell代码可以很深奥,有时编译器将无法推断该函数的类型。即使可以,对于那些不熟悉类型推断所需的抽象推理的人类读者也会有所帮助。在这种情况下,它是一种文档形式,但编译器强制执行正确性,不像(说)评论,它可以做到这一点。 – Kevin