Haskell如何知道你指的是哪个类型类实例?

时间:2023-01-06 17:03:42

This question arose while reading the new chapter in the excellent Learn You a Haskell about applicative functors.

在阅读关于应用函子的优秀的学习你的哈斯克尔的新章节时出现了这个问题。

The Applicative typeclass has, as part of the definition for the Maybe instance:

Applicative类型作为Maybe实例的定义的一部分:

pure = Just

If I just go to GHCi and import Control.Applicative, and do:

如果我只是去GHCi并导入Control.Applicative,并执行:

pure (3+)

I don't get Just anything (makes sense). But if I use it in part of the expression:

我没有得到任何东西(有道理)。但是如果我在表达式的一部分中使用它:

pure (3+) <*> Just 4

I get Just 7. I guess it also isn't surprising, but I'm missing something integral about how typeclasses work, I think, that there is no ambiguity with the call to pure here.

我得到的只是7.我想这也就不足为奇了,但是我错过了关于类型类如何工作的不可或缺的东西,我认为,这里对纯粹的调用没有任何歧义。

If my confusion makes sense, can anyone explain what's going on in detail?

如果我的困惑是有道理的,那么有人能解释一下详细情况吗?

4 个解决方案

#1


It's just type inference. The (<*>) operator requires both arguments to use the same Applicative instance. The right side is a Maybe, so the left side has to be a Maybe also. So that's how it figures out which instance is used here. You can look at the type of any expression in the interpreter by typing :t expression, and maybe if you just go through each subexpression and look at the type that was inferred, you will get a better picture of what's going on.

这只是类型推断。 (<*>)运算符要求两个参数都使用相同的Applicative实例。右边是一个可能,所以左侧必须是一个也许。这就是它如何确定这里使用的实例。您可以通过键入:t expression来查看解释器中任何表达式的类型,也许如果您只是浏览每个子表达式并查看推断出的类型,您将更好地了解正在发生的事情。

#2


It's worth looking at the type the compiler infers for pure (3+):

值得看一下编译器推断纯(3+)的类型:

Prelude Control.Applicative> :t pure (3+)
pure (3+) :: (Num a, Applicative f) => f (a -> a)

The type of this term is overloaded, and the decision about the numeric class and the applicative class is delayed until later. But you can force a particular type with an annotation, for example:

该术语的类型被重载,关于数字类和应用类的决定被推迟到以后。但是您可以使用注释强制特定类型,例如:

*Showfun Control.Applicative> pure (3+) :: Maybe (Double -> Double)
Just <function>

(This works because Showfun has an instance declaration that prints a function value as <function>.)

(这是有效的,因为Showfun有一个实例声明,它将函数值打印为 。)

It's just a question of when the compiler has accumulated enough information to make a decision.

这只是编译器何时积累了足够的信息来做出决定的问题。

#3


To expand a bit on newacct's answer, if there isn't enough information to infer the actual type, the compiler may (in some cases) attempt to select a default type, limited to those that would satisfy the type constraints in question. In this case, the type inferred is IO (n -> n) for some difficult-to-determine instance of Num => n. GHCi then evaluates it and throws away the return value, with no visible effect.

为了扩展newacct的答案,如果没有足够的信息来推断实际类型,编译器可能(在某些情况下)尝试选择默认类型,仅限于满足相关类型约束的类型。在这种情况下,对于某些难以确定的Num => n的实例,推断的类型是IO(n - > n)。然后GHCi对其进行评估并抛弃返回值,没有明显的效果。

#4


Here is an interesting SO thread on type inference. Not Haskell specific, but lots of good links and stuff to read about type inference in functional languages.

这是关于类型推断的一个有趣的SO线程。不是特定于Haskell,而是在函数式语言中阅读有关类型推断的许多好的链接和内容。

#1


It's just type inference. The (<*>) operator requires both arguments to use the same Applicative instance. The right side is a Maybe, so the left side has to be a Maybe also. So that's how it figures out which instance is used here. You can look at the type of any expression in the interpreter by typing :t expression, and maybe if you just go through each subexpression and look at the type that was inferred, you will get a better picture of what's going on.

这只是类型推断。 (<*>)运算符要求两个参数都使用相同的Applicative实例。右边是一个可能,所以左侧必须是一个也许。这就是它如何确定这里使用的实例。您可以通过键入:t expression来查看解释器中任何表达式的类型,也许如果您只是浏览每个子表达式并查看推断出的类型,您将更好地了解正在发生的事情。

#2


It's worth looking at the type the compiler infers for pure (3+):

值得看一下编译器推断纯(3+)的类型:

Prelude Control.Applicative> :t pure (3+)
pure (3+) :: (Num a, Applicative f) => f (a -> a)

The type of this term is overloaded, and the decision about the numeric class and the applicative class is delayed until later. But you can force a particular type with an annotation, for example:

该术语的类型被重载,关于数字类和应用类的决定被推迟到以后。但是您可以使用注释强制特定类型,例如:

*Showfun Control.Applicative> pure (3+) :: Maybe (Double -> Double)
Just <function>

(This works because Showfun has an instance declaration that prints a function value as <function>.)

(这是有效的,因为Showfun有一个实例声明,它将函数值打印为 。)

It's just a question of when the compiler has accumulated enough information to make a decision.

这只是编译器何时积累了足够的信息来做出决定的问题。

#3


To expand a bit on newacct's answer, if there isn't enough information to infer the actual type, the compiler may (in some cases) attempt to select a default type, limited to those that would satisfy the type constraints in question. In this case, the type inferred is IO (n -> n) for some difficult-to-determine instance of Num => n. GHCi then evaluates it and throws away the return value, with no visible effect.

为了扩展newacct的答案,如果没有足够的信息来推断实际类型,编译器可能(在某些情况下)尝试选择默认类型,仅限于满足相关类型约束的类型。在这种情况下,对于某些难以确定的Num => n的实例,推断的类型是IO(n - > n)。然后GHCi对其进行评估并抛弃返回值,没有明显的效果。

#4


Here is an interesting SO thread on type inference. Not Haskell specific, but lots of good links and stuff to read about type inference in functional languages.

这是关于类型推断的一个有趣的SO线程。不是特定于Haskell,而是在函数式语言中阅读有关类型推断的许多好的链接和内容。