我如何解释这个 SML 类型表达式?

How do I interpret this SML typing expression?

(* val bar = fn : (’a * ’b -> ’b) -> ’b -> ’a list -> ’b *)
fun bar f b nil = b
| bar f b (h::t) = f (h, bar f b t)

这个函数是通过解释它的作用的说明提供给我们的。给出的唯一进一步信息是参数是一个二元函数、一个值和一个列表。通过查看它,我已经知道如果列表为 nil,则它 returns b 值,否则它将二进制函数应用于列表头并递归。我只是不明白如何解释这一行:

(* val bar = fn : (’a * ’b -> ’b) -> ’b -> ’a list -> ’b *)

有许多教程解释了 SML 的类型,但我找不到任何足够深入的教程来应用它。谁能把它翻译成英文,以便我知道它是如何工作的以供将来参考?

我能够根据所谓的类型推断找到解决方案。我以前从未学过这个,但是

(* val bar = fn : (’a * ’b -> ’b) -> ’b -> ’a list -> ’b *)

是函数的参数和 return 类型的显示。

(’a * ’b -> ’b)指的是第一个参数函数。它本身需要 2 个参数('b'a)和 returns 1 个值 'b.

'b指的是第二个参数,一个值。

'a list 指的是值列表,函数中的第三个参数。

最后,最后的'b就是return的值。

要理解这个类型签名,你需要先理解currying

定义如

fun sum a b = a + b

类型为 int -> int -> int.

它是一个变量(一个整数)的函数,其中return值本身就是一个函数,一个将整数发送到整数的函数。

例如,val f = sum 1 将向其输入加一的函数(换句话说,后继函数)分配给 f,因此,例如,f 5 的计算结果为 6 .

在实践中,这样的函数经常像 sum 3 4 那样使用,但是那里发生的事情 不是 将 2 个值传递给 sum。相反,传递了一个值 3,return 是一个函数,然后将这个 returned 值应用于 4。因此,sum 3 4 应该被解析为 (sum 3) 4 而不是比 sum (3,4) -- 这将是一个类型错误。

请注意,这与

fun add (a,b) = a + b

其中两个变量的函数,它的类型是int * int -> int,与sum的int -> int -> int类型不同。后者不是前者的语法糖,而是具有根本不同的语义。

当阅读诸如 int -> int -> int 之类的内容时,您应该将其阅读为右结合。换句话说,它与 int -> (int -> int).

相同

('a * 'b -> 'b) -> 'b -> 'a list -> 'b 发生的另一件事是使用 类型变量 'a, 'b。这意味着您要解析的类型是高阶 polymorphic 函数。它'a'b可以表示任何类型。

将它们放在一起,('a * 'b -> 'b) -> 'b -> 'a list -> 'b 类型的函数 f 是一个将类型为 'a * 'b -> 'b 形式的任何函数作为输入的函数(函数return 类型为第二个变量类型的两个变量)。 f 的 return 值是 'b -> 'a list -> 'b 形式的函数。后者是一个接受 'b 类型元素的函数,return 是一个将 'a lists 发送到 'b

类型对象的函数

你可以这样总结它 f 是一个 curried 函数,它接受一个 ('a * 'b -> 'b) 类型的函数,一个 [=29] 类型的值=],'a 类型的值列表,return 是 'b 类型的值。这足够准确,但不要误以为它等同于类型

的函数
('a * 'b -> 'b) * 'b * 'a list -> 'b

顺便说一下,SML 中两个最有用的函数 foldlfoldr 的类型为 ('a * 'b -> 'b) -> 'b -> 'a list -> 'b,因此这不仅仅是一个学术练习。能够解包这样的类型描述是能够正确使用这些函数的关键。