问题描述
在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
激励)。
另请参见