我经常阅读有关功能:
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 ()
任何人都可以帮助我理解这个功能吗?
问题是fun constantly k a = k
有类型'a -> 'b -> 'a
像constantly 10
这样的部分函数调用将被视为一个扩展表达式,并且SML期望能够在此时推断出constantly
的类型变量的实际类型。也就是说,SML期望它可以用一些具体类型的'a
替换类型变量'b
和T
。
由于您的参数a
未在constantly
函数的主体中使用,因此SML无法推断出任何有关它的信息。
你会期望像val a = constantly 10
这样的表达式产生类似'b -> int
的类型,但是,因为SML发现它无法确定'b
的类型然后它改变它为虚拟(具体)类型?.X1
,这就是为什么你最终得到一个函数键入?.X1 -> int
。
这只是SML告诉你,它无法正确推断'b
,因为你没有在扩展表达式中为它提供足够的类型信息,所以它为它分配了一个虚拟具体类型,这基本上使你的函数无法使用。
因此,对另一篇文章中已经提到的解决方案的替代解决方案是使用具体类型限定您的结果函数。
例如,这应该工作:
val a = constantly 10: (int -> int)
因此,将类型变量'b
限定为int
的明显缺点是,curried函数a
不再是多态函数,但它确实是一个curried函数。为了实现这个目的,我们需要知道在我们创建curried函数时'b
的具体类型。
但是如果你仍然需要curried函数是多态的,因为你不能在那时为'b
假设一个特定/具体的类型,那么,正如另一个答案所提到的,你将需要提供另一个带有你的多态类型的参数:
val a = fn x => constantly 10 x
在seanmcl的回答中,这基本上是一回事。
这样可行,因为现在x
会在你的包装函数中调用'b
时携带constantly 10 x
的具体类型。当你调用curried函数a
(即val _ = a(15)
在这种情况下'b
是int
)时,将定义这样的具体类型
这是价值限制。了解它对于了解ML中的部分应用非常重要。由于多态性存在的可变性,这是必要的。
http://mlton.org/ValueRestriction http://users.cis.fiu.edu/~smithg/cop4555/valrestr.html
每次看到这样的警告时,都可以通过eta扩展表达式来修复它。
fun a x = constantly 10 x;