当我在像带有Prelude的GHCI这样的REPL中时,我写
*> compare 5 7
LT
Run Code Online (Sandbox Code Playgroud)
为什么我compare可以在REPL中直接调用该函数()?
我知道compare是在typeclass中定义的Ord。类型类的定义Ord当然表明它是的子类Eq。
这是我的推理路线:
5具有type Num a => a,并且Numtypeclass不是的子类Eq。也,
Prelude> :t (compare 5)
(compare 5) :: (Num a, Ord a) => a -> Ordering
Run Code Online (Sandbox Code Playgroud)
因此,当我应用数字类型参数时,这里还有一个附加的约束。当我打电话时compare 5 7,参数的类型缩小到确实有一个实例的东西Ord。我认为范围的缩小发生在与typeclass相关联的默认具体类型上:在的情况下Num,这是Integer,其实例为Real,其实例为Ord。
但是,由于来自非功能性编程背景,我会想象必须调用compare其中一个数字(例如,在OOP中的对象上对其进行调用)。如果5is是Integer实现的Ord,那为什么我要调用compareREPL本身呢?对于我来说,这显然是一个与范式转换有关的问题,但我仍然没有理解。希望有人可以解释。
诸如此类compare的方法与类型相关联,而不与特定值相关联。编译器需要能够推断出类型,以便选择正确的typeclass实例,但这不需要任何特殊帮助。
的类型compare是
compare :: (Ord a) => a -> a -> Ordering
Run Code Online (Sandbox Code Playgroud)
因此,其任何参数(类型为a)都可以用于查找Ord实例。
如您所正确假设的那样,在compare 5 7示例中,类型为5,7默认为Integer。因此a,compare推导类型为,Integer并Ord Integer选择实例。
该选择不一定要通过函数参数。考虑例如
read :: (Read a) => String -> a
Run Code Online (Sandbox Code Playgroud)
这是驱动实例选择的结果类型,但是类型检查器就可以了:
> read "(2, 3)" :: (Int, Int)
(2,3)
Run Code Online (Sandbox Code Playgroud)
(相当于OO的是什么"(2, 3)".read()??)
实际上,方法甚至不必一定是函数:
maxBound :: (Bounded a) => a
Run Code Online (Sandbox Code Playgroud)
这是一个多态值,而不是一个函数:
> maxBound :: Int
9223372036854775807
Run Code Online (Sandbox Code Playgroud)
类实例是唯一地与类型相关联的,因此,只要类型检查器具有足够的信息来找出该类型变量所代表的内容,一切都会正常进行。也就是说,在
someMethod :: (SomeClass foo) => ...
Run Code Online (Sandbox Code Playgroud)
foo必须在类型签名中的某个位置出现,...以便类型检查器可以解决在任何给定点使用SomeClass foo的方式someMethod(至少在没有某些语言扩展的情况下)。