3

我最近注意到在函数声明中允许在函数名之前使用类型变量。但我看不到它是如何使用的。以下是一些使用它的示例:

Poly/ML 5.5.2 Release
> fun 'a print a = PolyML.print (a);
val print = fn: 'a -> 'a
> print "foo";
?
val it = "foo": string
> pint string "foo";
Error-Value or constructor (string) has not been declared
Found near print string "foo"
Static Errors
> string print "foo";
Error-Value or constructor (string) has not been declared
Found near string print "foo"
Static Errors
> val f : string -> string = print;
val f = fn: string -> string
> f "foo";
?
val it = "foo": string

因此,基于此,我有几个问题。首先,什么是函数名之前的类型变量用例的一个很好的例子(与参数或返回类型签名中更常见的类型变量相反)。另外,有没有办法表明我想专注于类型,就像我可以使用类型一样?:

> type 'a t = 'a list;
eqtype 'a t
> type f = string t;
type f = string t

我确实通过创建一个val f具有显式类型签名的新变量 来声明特化,但我认为这不是一回事。例如,来自上面的类型示例,我希望能够做到这一点:

> val s = string print;
Error-Value or constructor (string) has not been declared Found near string print
Static Errors

但这失败了。

最后,为什么类型变量在函数内部隐藏了参数的类型?我只是猜测会发生这种情况,因为 PolyML.print 函数会打印一个问号(表示它不知道类型)而不是实际值。即使我声明了f明确约束类型的新函数,它仍然不知道传递的变量的类型。(虽然我很确定这个特定部分与函数上的初始类型变量无关,而是与参数上的(隐式)类型变量无关a。)

4

1 回答 1

5

紧跟在 a 之后的类型变量的想法fun是它限定了类型变量的后续使用。考虑之间的差异

> fun f x =
# let
#     fun I (y:'a): 'a = y
# in
#     I I
# end;
val f = fn: 'a -> 'b -> 'b

> fun 'a f x =
# let
#     fun I (y:'a): 'a = y
# in
#     I I
# end;
Type error in function application.
   Function: I : 'a -> 'a
   Argument: I : 'a -> 'a
   Reason:
      Can't unify 'a to 'a -> 'a (Cannot unify with explicit type variable)

第一个类型检查因为一般使用I可以专门针对不同的类型。第二个不是,因为通过在您所说的乐趣范围内确定类型变量的范围,这I在该级别上不应该是可推广的。你说过你希望所有出现的'ainsidef都是一样的。

ML 为值和类型以及不同类型的模块具有单独的名称空间。 string被定义为一种类型,但如果您在预期值的上下文中使用此标识符,它将是未定义的。您需要添加类型约束,例如: string -> string

最后,小心使用PolyML.print作为示例。它不是一个普通的 ML 多态函数,而是一个无限重载的函数,它在编译时根据类型信息打印其参数。它是 Poly/ML 扩展,这就是为什么它存在于 PolyML 结构中,尽管print它出现在标准 ML 的早期草案中。

于 2016-03-17T09:23:07.387 回答