考虑以下Haskell函数:
sign a
| a < 0 = (-1)
| a > 0 = 1
| otherwise = 0
Run Code Online (Sandbox Code Playgroud)
当我把它加载到ghci我希望:t sign是:
sign :: (Num a, Ord a) => a -> Integer
Run Code Online (Sandbox Code Playgroud)
相反,它推断为:
*Main> :t sign
sign :: (Num a1, Num a, Ord a1) => a1 -> a
Run Code Online (Sandbox Code Playgroud)
同样,如果我要求整数的类型5,我期望Integer,但我得到了
*Main> :t 5
5 :: Num a => a
Run Code Online (Sandbox Code Playgroud)
我不了解Haskell的类型.问题是,如果我所知道的返回类型sign是它是Num类型类的一个实例,那么我不应该将它的返回值传递给这个函数:
double :: Integer -> Integer
double x = x * 2
Run Code Online (Sandbox Code Playgroud)
也就是说,我的double函数需要一个Integer,而不仅仅是任何实例Num.
然而,以下工作正常:
*Main> double (sign 5.5)
2
Run Code Online (Sandbox Code Playgroud)
我对Haskell的类型系统的误解是什么?
Dan*_*her 19
问题是,如果我所知道的'sign'的返回类型是它是
Num类型类的实例,那么我就不能将它的返回值传递给这个函数:
是的,如果这就是你所知道的,你就无法将它传递给double.
但是类型
sign :: (Num a1, Num a, Ord a1) => a1 -> a
Run Code Online (Sandbox Code Playgroud)
表示结果类型sign是调用者要求的任何 Num类型.类型签名中的类型变量是(隐式地)普遍量化的,而不是存在性的,例如Java接口.
sign可以产生任意类型的返回值,受限于它是一个实例Num,并且它返回的类型由调用上下文决定.
如果呼叫者想要一个Integer,它就会得到一个.如果它想要一个Double,也没问题.
我最初忘了提到:
同样,如果我要求整数5的类型,我期望"整数",但我得到了
*Main> :t 5
5 :: Num a => a
Run Code Online (Sandbox Code Playgroud)
数字文字是多态的,整数文字代表fromInteger value,和小数文字fromRational value.
Ben*_*son 10
我只是想澄清@ DanielFischer的答案.A型签名像f :: Num b => a -> b装置,其f能够返回的任何的类型类的实例Num.当f被调用时,Haskell使用的上下文(呼叫者的类型签名)来确定具体类型的b.
而且,Haskell的数字文字就是这种多态的一个例子.这就是为什么:t 5给你的原因Num a => a.该符号5能够充当任何类型的数字,而不仅仅是整数.它出现的上下文决定了它将是什么.
在Haskell中,如果函数返回type x是其结果,则意味着调用者可以选择x应该是什么,而不是函数.相反,该函数必须能够返回任何可能的类型.
您sign可以返回任何类型的数据 - 包括Integer.该double功能要的Integer,所以这只是罚款- sign可以返回.
你可能不知道的另一部分难题:在Java中,2有类型int和2.0类型double.但在Haskell中,2有类型Num x => x- 换句话说,任何可能的数字类型.(也2.0有类型Fractional x => x,这是类似的交易.)