Haskell 如何知道你指的是哪个类型类实例?
-
03-07-2019 - |
题
这个问题是在阅读有关应用函子的优秀《Learn You a Haskell》的新章节时出现的。
作为 Maybe 实例定义的一部分,Applicative 类型类具有:
pure = Just
如果我只是转到 GHCi 并导入 Control.Applicative,然后执行以下操作:
pure (3+)
我什么也没得到(有道理)。但如果我在表达式的一部分中使用它:
pure (3+) <*> Just 4
我只得到7。我想这也不足为奇,但我认为,我缺少关于类型类如何工作的一些完整内容,即调用没有歧义 pure
这里。
如果我的困惑有道理,谁能详细解释一下发生了什么?
解决方案
这只是类型推断。 (<*>)
运算符需要两个参数才能使用相同的Applicative
实例。右侧是Maybe
,所以左侧也必须是:t expression
。这就是它如何确定这里使用的实例。您可以通过键入<=>来查看解释器中任何表达式的类型,也许如果您只是浏览每个子表达式并查看推断的类型,您将更好地了解正在发生的情况。
其他提示
值得查看编译器推断的类型pure (3+)
:
Prelude Control.Applicative> :t pure (3+)
pure (3+) :: (Num a, Applicative f) => f (a -> a)
此术语的类型已重载,关于数字类和应用类的决定会延迟到稍后。但您可以使用注释强制特定类型,例如:
*Showfun Control.Applicative> pure (3+) :: Maybe (Double -> Double)
Just <function>
(这是因为Showfun
有一个实例声明,它将函数值打印为<function>
。)
这只是编译器何时积累了足够的信息才能做出决定的问题。
要扩展newacct的答案,如果没有足够的信息来推断实际类型,编译器可能(在某些情况下)尝试选择默认类型,仅限于满足相关类型约束的类型。在这种情况下,对于某些难以确定的Num = <!> gt的实例,推断的类型是IO(n - <!>>; n); ñ。然后GHCi对其进行评估并抛弃返回值,但没有明显效果。
这是一个有趣的 SO 线程类型推断. 。不是 Haskell 特有的,但是有很多关于函数式语言中类型推断的好链接和内容可供阅读。