为什么这两个标准 ML 函数的签名不同?
Why is the signature different for these two Standard ML functions?
我正在尝试实现一个检查列表是否为空的函数(类似于 List.null
)。
这有签名 val isEmpty = fn: ''a list -> bool
:
fun isEmpty ls =
ls = []
这有签名 val isEmpty = fn: 'a list -> bool
:
fun isEmpty [] = true
| isEmpty _ = false
为什么这两个函数的签名不同,尽管它们做同样的事情?
这里发生的事情的一个重要提示是(在 SML/NJ 中)第一个定义触发 Warning: calling polyEqual
。它基于列表比较,但在 SML 中只对相等类型有意义。当您执行类似
的操作时,您的第一个定义失败
isEmpty [1.0, 2.1];
而其他两个定义没有问题。因此——这三个定义不会“做同样的事情”。他们几乎做到了,但不完全是。
有关该警告的更多信息,请参阅 Warning: calling polyequal。
主要原因是第一个版本比第二个版本更强大。相等运算符具有以下类型,它将约束第一个版本的类型签名:
$ sml
Standard ML of New Jersey (64-bit) v110.99.2 [built: Thu Sep 23 13:44:44 2021]
- op =;
val it = fn : ''a * ''a -> bool
''a
约束传播到封闭函数定义。
第二个版本没有使用该运算符,因为它不需要,它只需要查看列表的形状,而不是其组成元素。我们可以将其脱糖以使其更明显:
fun isEmpty list =
case list of
| nil => true
| _ :: _ => false
很明显,它不关心这些元素,而另一个可能关心,即使在您的特定情况下它不关心。例如:
fun isPalindrome list =
list = List.rev list
我正在尝试实现一个检查列表是否为空的函数(类似于 List.null
)。
这有签名 val isEmpty = fn: ''a list -> bool
:
fun isEmpty ls =
ls = []
这有签名 val isEmpty = fn: 'a list -> bool
:
fun isEmpty [] = true
| isEmpty _ = false
为什么这两个函数的签名不同,尽管它们做同样的事情?
这里发生的事情的一个重要提示是(在 SML/NJ 中)第一个定义触发 Warning: calling polyEqual
。它基于列表比较,但在 SML 中只对相等类型有意义。当您执行类似
isEmpty [1.0, 2.1];
而其他两个定义没有问题。因此——这三个定义不会“做同样的事情”。他们几乎做到了,但不完全是。
有关该警告的更多信息,请参阅 Warning: calling polyequal。
主要原因是第一个版本比第二个版本更强大。相等运算符具有以下类型,它将约束第一个版本的类型签名:
$ sml
Standard ML of New Jersey (64-bit) v110.99.2 [built: Thu Sep 23 13:44:44 2021]
- op =;
val it = fn : ''a * ''a -> bool
''a
约束传播到封闭函数定义。
第二个版本没有使用该运算符,因为它不需要,它只需要查看列表的形状,而不是其组成元素。我们可以将其脱糖以使其更明显:
fun isEmpty list =
case list of
| nil => true
| _ :: _ => false
很明显,它不关心这些元素,而另一个可能关心,即使在您的特定情况下它不关心。例如:
fun isPalindrome list =
list = List.rev list