在函数名称和结果范围限制之前键入变量

eat*_*hil 3 sml polyml

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

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
Run Code Online (Sandbox Code Playgroud)

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

> type 'a t = 'a list;
eqtype 'a t
> type f = string t;
type f = string t
Run Code Online (Sandbox Code Playgroud)

我确实通过创建一个val f带有显式类型签名的新变量来声明一个特化,但我认为这不是同一个东西.例如,来自上面的类型示例我希望能够这样做:

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

但那失败了.

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

Dav*_*ews 5

在a之后立即使用类型变量的想法fun是它在后续使用类型变量的范围.考虑两者之间的差异

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

> 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)
Run Code Online (Sandbox Code Playgroud)

第一种类型检查因为一般使用I可以专门针对不同类型.第二个不是因为通过确定类型变量的范围,你所说的乐趣I不应该在那个级别上是通用的.您已经说过,您希望所有出现的'a内部f都相同.

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

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