我不断阅读有关功能的内容:
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 ()
有人能帮助我理解这个功能吗?
答案 0 :(得分:1)
这是价值限制。了解它对于了解ML中的部分应用非常重要。由于多态性存在的可变性,这是必要的。
http://mlton.org/ValueRestriction http://users.cis.fiu.edu/~smithg/cop4555/valrestr.html
每次看到这样的警告时,都可以通过eta扩展表达来修复它。
fun a x = constantly 10 x;
答案 1 :(得分:0)
问题是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
}