由推断的表达式类型覆盖的类型注释
type annotations overriden by inferred expression type
在 scala 编程语言中,假设我将用更广泛的类型注释表达式并提供一个窄值,我的程序被拒绝:
scala> def x[A](): A = 8
<console>:11: error: type mismatch;
found : Int(8)
required: A
def x[A]() = 8: A
而在 ocaml 中,当我做同样的事情时,程序被接受,但表达式的类型注释被更窄表达式的类型覆盖。
utop # let x (): 'a = 8 ;;
val x : unit -> int = <fun>
这些类型系统之间的区别是什么,导致一种情况下程序被拒绝而另一种情况下程序被接受?
我完全不懂ocaml。但是根据:val x : unit -> int = <fun>
ocaml 似乎可以推断出您声明的函数的 return 类型,即 int.
在Scala中,当你声明def x[A](): A
时,你定义了一个函数,我们来详细说明这个函数是什么意思:
- 函数的名称是
x
。
- 这个函数是通用的,期望得到一个类型
A
。
- 该函数没有参数。
- return类型是
A
。
在这样的函数 8 中 return 时,编译器尝试将 8 转换为 A
失败。
您要执行的操作类似于:
scala> def x[A](): Int = 8
x: [A]()Int
@craigfe 实际上昨天刚刚写了 a very accessible post,我强烈建议阅读。
但简短的回答是,OCaml 注释中的类型变量是统一变量,而不是多态类型约束。它们表示要由编译器推断的未知类型,编译器将更喜欢更通用的解决方案,并可能将其推断为多态,但如果不可能,则将其推断为特定类型。
为了得到你期望的行为,你必须明确指出类型变量应该使用'a.
进行普遍量化,通常读作“for all a's”:
utop # let x: 'a. unit -> 'a = fun () -> 8 ;;
^^^^^^^^^^^
Error: This definition has type unit -> int which is less general than
'a. unit -> 'a
在Scala中允许不指定return类型,那么它会被推断
def x() = 8
x(): Int
如果你确实想指定 return 类型,那么,我想你可以使用助手 class
在 Scala 中模拟类型参数的 OCaml 行为
val t = TypeOf(8)
def x(): t.A = t.a
case class TypeOf[_A](a: _A) {
type A = _A
}
或
val t = TypeOf(8)
def x(): t.A = 8
implicit class TypeOf[_A](a: _A) {
type A = _A
}
甚至
def x(): TypeOf.`8`.A = 8
import scala.language.dynamics
import scala.language.experimental.macros
import scala.reflect.macros.whitebox
object TypeOf extends Dynamic {
def selectDynamic(term: String): Any = macro selectDynamicImpl
def selectDynamicImpl(c: whitebox.Context)(term: c.Tree): c.Tree = {
import c.universe._, internal.decorators._
val q"${termStr: String}" = term
val termType = c.typecheck(c.parse(termStr), silent = false).tpe
val resType = c.typecheck(tq"{ type A = $termType }", mode=c.TYPEmode, silent = false).tpe
q"()".setType(resType)
}
}
(受到 shapeless.Witness.selectDynamic
的启发)。
另见
T <: A, return T method
在 scala 编程语言中,假设我将用更广泛的类型注释表达式并提供一个窄值,我的程序被拒绝:
scala> def x[A](): A = 8
<console>:11: error: type mismatch;
found : Int(8)
required: A
def x[A]() = 8: A
而在 ocaml 中,当我做同样的事情时,程序被接受,但表达式的类型注释被更窄表达式的类型覆盖。
utop # let x (): 'a = 8 ;;
val x : unit -> int = <fun>
这些类型系统之间的区别是什么,导致一种情况下程序被拒绝而另一种情况下程序被接受?
我完全不懂ocaml。但是根据:val x : unit -> int = <fun>
ocaml 似乎可以推断出您声明的函数的 return 类型,即 int.
在Scala中,当你声明def x[A](): A
时,你定义了一个函数,我们来详细说明这个函数是什么意思:
- 函数的名称是
x
。 - 这个函数是通用的,期望得到一个类型
A
。 - 该函数没有参数。
- return类型是
A
。
在这样的函数 8 中 return 时,编译器尝试将 8 转换为 A
失败。
您要执行的操作类似于:
scala> def x[A](): Int = 8
x: [A]()Int
@craigfe 实际上昨天刚刚写了 a very accessible post,我强烈建议阅读。
但简短的回答是,OCaml 注释中的类型变量是统一变量,而不是多态类型约束。它们表示要由编译器推断的未知类型,编译器将更喜欢更通用的解决方案,并可能将其推断为多态,但如果不可能,则将其推断为特定类型。
为了得到你期望的行为,你必须明确指出类型变量应该使用'a.
进行普遍量化,通常读作“for all a's”:
utop # let x: 'a. unit -> 'a = fun () -> 8 ;;
^^^^^^^^^^^
Error: This definition has type unit -> int which is less general than
'a. unit -> 'a
在Scala中允许不指定return类型,那么它会被推断
def x() = 8
x(): Int
如果你确实想指定 return 类型,那么,我想你可以使用助手 class
在 Scala 中模拟类型参数的 OCaml 行为val t = TypeOf(8)
def x(): t.A = t.a
case class TypeOf[_A](a: _A) {
type A = _A
}
或
val t = TypeOf(8)
def x(): t.A = 8
implicit class TypeOf[_A](a: _A) {
type A = _A
}
甚至
def x(): TypeOf.`8`.A = 8
import scala.language.dynamics
import scala.language.experimental.macros
import scala.reflect.macros.whitebox
object TypeOf extends Dynamic {
def selectDynamic(term: String): Any = macro selectDynamicImpl
def selectDynamicImpl(c: whitebox.Context)(term: c.Tree): c.Tree = {
import c.universe._, internal.decorators._
val q"${termStr: String}" = term
val termType = c.typecheck(c.parse(termStr), silent = false).tpe
val resType = c.typecheck(tq"{ type A = $termType }", mode=c.TYPEmode, silent = false).tpe
q"()".setType(resType)
}
}
(受到 shapeless.Witness.selectDynamic
的启发)。
另见
T <: A, return T method