由推断的表达式类型覆盖的类型注释

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