Scala 是否保证在存在隐式时的连贯性?
Does Scala guarantee coherence in the presence of implicits?
文章Type classes: confluence, coherence and global uniqueness提出以下几点-
[Coherence] states that every different valid typing derivation of a program leads to a resulting program that has the same dynamic semantics.
[..]
So, what is it that people often refer to when they compare Scala type classes to Haskell type classes? I am going to refer to this as global uniqueness of instances, defining to say: in a fully compiled program, for any type, there is at most one instance resolution for a given type class. Languages with local type class instances such as Scala generally do not have this property, but in Haskell, we find this property is a very convenient one when building abstractions like sets.
如果您在 Modular implicits 上查看这篇论文,它指出 -
[..] Scala’s coherence can rely on the weaker property of non-ambiguity
instead of canonicity. This means that you can define multiple implicit objects of type Showable[Int]
in your program without causing an error. Instead, Scala issues an error if the resolution of an implicit
parameter is ambiguous. For example, if two implicit objects of type Showable[Int] are in scope when
show is applied to an Int then the compiler will report an ambiguity error.
这两者给人的印象是Scala确实保证了一致性,但没有保证实例的全局唯一性。
但是,如果您查看 Martin Odersky 的评论 (1, 2),似乎连贯性一词被用作 shorthand“实例的唯一性”,这将解释术语“局部一致性”和“全局一致性”。
这是否只是同一个术语被用来表示两个不同事物的不幸案例?它们当然是不同的——OCaml 的模块化隐含确保一致性(根据第一个定义)但不是实例的全局唯一性。
Scala 是否保证在隐式存在的情况下的连贯性(根据第一个定义)?
我认为在这种情况下它们的意思是一样的。只有当你有不止一种推导 instance/implicit 值的方法时,一致性才会受到质疑; "every different valid typing derivation" 仅当 是 不止一次键入推导时才有趣。 Scala 和 Haskell 都不允许在编译时出现可能导致歧义推导的实例。
斯卡拉
Odersky 的评论是针对 Scala 的:只有一种 local 解析实例的方法。换句话说,只有一个有效的本地类型派生。很简单,它与自身是一致的。我不清楚在 Scala 中讨论全局一致性是否有意义,但如果有的话,Scala 肯定没有:
object Object1 {
implicit val i: Int = 9
println(implicitly[Int]) // valid typing derivation of `Int` => printing 9
}
object Object2 {
implicit val i: Int = 10
println(implicitly[Int]) // valid typing derivation of `Int` => printing 10
}
Haskell
由于Haskell实例是全局的,因此区分local/global连贯性没有意义。
Haskell 不允许在编译时有两个实例,其中一个实例头与另一个实例头重叠。这将寻找类型推导变成了一个明确的非回溯搜索问题。明确性再次让我们保持一致。
有趣的是,GHC 允许您通过 -XIncoherentInstances
放宽此要求,允许您编写本地非融合实例,也可能破坏全局一致性。
文章Type classes: confluence, coherence and global uniqueness提出以下几点-
[Coherence] states that every different valid typing derivation of a program leads to a resulting program that has the same dynamic semantics.
[..]
So, what is it that people often refer to when they compare Scala type classes to Haskell type classes? I am going to refer to this as global uniqueness of instances, defining to say: in a fully compiled program, for any type, there is at most one instance resolution for a given type class. Languages with local type class instances such as Scala generally do not have this property, but in Haskell, we find this property is a very convenient one when building abstractions like sets.
如果您在 Modular implicits 上查看这篇论文,它指出 -
[..] Scala’s coherence can rely on the weaker property of non-ambiguity instead of canonicity. This means that you can define multiple implicit objects of type Showable[Int] in your program without causing an error. Instead, Scala issues an error if the resolution of an implicit parameter is ambiguous. For example, if two implicit objects of type Showable[Int] are in scope when show is applied to an Int then the compiler will report an ambiguity error.
这两者给人的印象是Scala确实保证了一致性,但没有保证实例的全局唯一性。
但是,如果您查看 Martin Odersky 的评论 (1, 2),似乎连贯性一词被用作 shorthand“实例的唯一性”,这将解释术语“局部一致性”和“全局一致性”。
这是否只是同一个术语被用来表示两个不同事物的不幸案例?它们当然是不同的——OCaml 的模块化隐含确保一致性(根据第一个定义)但不是实例的全局唯一性。
Scala 是否保证在隐式存在的情况下的连贯性(根据第一个定义)?
我认为在这种情况下它们的意思是一样的。只有当你有不止一种推导 instance/implicit 值的方法时,一致性才会受到质疑; "every different valid typing derivation" 仅当 是 不止一次键入推导时才有趣。 Scala 和 Haskell 都不允许在编译时出现可能导致歧义推导的实例。
斯卡拉
Odersky 的评论是针对 Scala 的:只有一种 local 解析实例的方法。换句话说,只有一个有效的本地类型派生。很简单,它与自身是一致的。我不清楚在 Scala 中讨论全局一致性是否有意义,但如果有的话,Scala 肯定没有:
object Object1 {
implicit val i: Int = 9
println(implicitly[Int]) // valid typing derivation of `Int` => printing 9
}
object Object2 {
implicit val i: Int = 10
println(implicitly[Int]) // valid typing derivation of `Int` => printing 10
}
Haskell
由于Haskell实例是全局的,因此区分local/global连贯性没有意义。
Haskell 不允许在编译时有两个实例,其中一个实例头与另一个实例头重叠。这将寻找类型推导变成了一个明确的非回溯搜索问题。明确性再次让我们保持一致。
有趣的是,GHC 允许您通过 -XIncoherentInstances
放宽此要求,允许您编写本地非融合实例,也可能破坏全局一致性。