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

问题描述

在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>

这两种类型的系统有什么区别,导致一种情况,即程序被拒绝,而另一种程序被接受?

解决方法

@craigfe实际上昨天刚刚写了a very accessible post,我强烈建议阅读。

但是简短的答案是,OCaml注释中的类型变量是统一变量,而不是多态类型约束。它们表示要由编译器推断的未知类型,它们将首选更通用的解决方案,并可能将其推断为多态的,但如果不可能,则将其推断为特定类型。

为了获得您期望的行为,您必须明确指出类型变量应该使用'a.进行通用量化,通常读作“ for all a”:

utop # let x: 'a. unit -> 'a = fun () -> 8 ;;
                               ^^^^^^^^^^^
Error: This definition has type unit -> int which is less general than
         'a. unit -> 'a
,

我一点也不懂ocaml。但是根据val x : unit -> int = <fun>,看来ocaml可以推断您声明的函数的返回类型,即int。

在Scala中,当您声明def x[A](): A时,您定义了一个函数,然后详细说明该函数的含义:

  • 函数的名称为x
  • 此函数是通用函数,期望获得类型A
  • 该函数没有参数。
  • 返回类型为A

返回此类函数8时,编译器尝试将8转换为A失败。

您要尝试执行的操作类似于:

scala> def x[A](): Int = 8 
x: [A]()Int
,

在Scala中,可以不指定返回类型,然后将其推断出来

def x() = 8 
x(): Int

我想,如果您确实想指定返回类型,则可以使用辅助类在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