0

我不断阅读有关功能的信息:

fun constantly k a = k

但我不明白如何使用它。我试过这样:

val a = constantly 10;
stdIn:32.5-32.28 Warning: type vars not generalized because of
  value restriction are instantiated to dummy types (X1,X2,...)
  val a = fn : ?.X1 -> int * int -> int

它是这样工作的:

val a = constantly 10 ();
  val a : int = 10

但不是这样:

val a = constantly 10;
a ();
stdIn:36.1-36.5 Error: operator and operand don't agree [tycon mismatch]
operator domain: ?.X1
operand:         unit
in expression:
  a ()

任何人都可以帮助我理解该功能吗?

4

2 回答 2

1

这就是价值限制。理解 ML 中的部分应用很重要。由于多态性存在的可变性,这是必要的。

http://mlton.org/ValueRestriction http://users.cis.fiu.edu/~smithg/cop4555/valrestr.html

任何时候你看到这样的警告,你都可以通过 eta 扩展表达式来修复它。

fun a x = constantly 10 x;
于 2013-10-21T14:20:38.310 回答
0

事情是fun constantly k a = k有类型'a -> 'b -> 'a

像这样的部分函数调用constantly 10将被视为扩展表达式,并且 SML 预计此时能够推断出类型变量的实际类型constantly。也就是说,SML 期望它可以在此时替换类型变量'a'b使用一些具体类型T

由于您的参数a未在constantly函数体中使用,因此 SML 无法推断出任何关于它的信息。

您会期望表达式 likeval a = constantly 10产生类似 的类型'b -> int,但是相反,由于 SML 发现它无法确定的类型,'b然后将其更改为 dummy (concrete) type ?.X1,这就是您最终得到 function type 的原因?.X1 -> int

这只是 SML 告诉您它无法正确推断'b,因为您没有在扩展表达式中为其提供足够的类型信息,因此它为其分配了一个虚拟的具体类型,这基本上使您的函数无法使用。

因此,对于另一篇文章中已经提到的解决方案,另一种解决方案是使用具体类型限定生成的函数。

例如,这应该有效:

val a = constantly 10: (int -> int)

由于将类型变量限定为 的明显缺点'bint因此,柯里化函数a不再是多态函数,但它确实是柯里化函数。为此,我们需要知道'b创建柯里化函数时的具体类型。

但是,如果您仍然需要 curried 函数是多态的,因为此时您不能假设特定/具体类型,'b那么正如另一个答案所提到的,您将需要提供另一个带有您的多态类型的参数:

val a = fn x => constantly 10 x

这与 seanmcl 的回答基本相同。

这会起作用,因为 nowx会将'b调用中的具体类型 for 带到constantly 10 x包装器函数中。这样的具体类型将在您调用 curried 函数时定义a(即val _ = a(15)在这种情况下'bint

于 2013-10-21T16:28:55.537 回答