我正在阅读Harper的书,标准ML简介,并且在第11.3节“返回函数”中有点困惑。
1)他定义了一个创建常数函数的函数。他写道:
"给定值k,应用程序constantly k
生成一个函数,无论何时应用它都会产生k
。这是constantly
:
val constantly = fn k => (fn a => k)
该功能始终具有'a -> ('b -> 'a)
类型。"这对我来说很有意义:你提供了一个类型为' a的值,它返回一个总是返回该值(类型为' a)的函数,无论输入是什么(类型为' b,可能与a&a; a)类型相同或不同。
但他说我们也可以将此功能定义为:
fun constantly k a = k
这看起来像一个函数,它接受两个参数并返回第一个......但不是一个返回另一个函数的函数...
我错过了什么?
2)稍后,哈珀讨论了一个地图功能。我理解基本的地图功能。然后他讨论了一个map函数,它允许我们将传入的函数应用于许多列表(而不是使用相同的传入函数调用我们的原始映射函数多次)。他写道:
fun map' f nil = nil
| map' f (h::t) = (f h) :: (map' f t)
"如此定义的函数映射具有类型('a -> 'b) -> 'a list -> 'b list
。它需要类型' a - >的功能。 ' b作为参数,并产生类型为'a list -> 'b list
的另一个函数。"
我很丢失,因为它看起来像地图'只需将f应用于列表中的所有元素并返回结果列表。所以我原以为它会是类型:
('a -> 'b) * 'a list -> 'b list
我哪里错了?
感谢您的帮助, bclayman
答案 0 :(得分:5)
你的两个问题都源于对函数的实际参数缺乏清晰度。在SML中,每个函数(回想一下函数是值)只需要一个参数。该参数可能是一个元组(类型'a * 'b
但它仍然是一个参数(需要被解构)。
在SML中,fun f x1 x2 ... = T
是val rec f = fn x1 => fn x2 => ... => T
的语法糖。因此constantly k
评估为fn a => k
。
是否为地图提供类型('a -> 'b) * 'a list -> 'b list
或('a -> 'b) -> 'a list -> 'b list
是图书馆设计问题,但效果是一样的。他们做同样的事情,虽然第一个采用函数和列表的元组,而第二个采用函数优先,并从列表返回一个函数到列表。这被称为" currying"在编程语言文学中。 (元组版本是"没有结果",另一个是"咖喱"。)
答案 1 :(得分:5)
这个神奇的词是" currying":https://en.wikipedia.org/wiki/Currying
在ML(以及Haskell)函数应用程序中绑定比任何其他运算符更紧密。因此constantly k a
解析为(constantly k) a
。 constantly k
绑定到一个函数。要了解什么功能,您可以在心理上考虑定义
fun constantly k a = k
等同于
fun (constantly k) a = k
这表示(constantly k)
是将任何a映射到k的函数。
因此,其类型为'a -> ('b -> 'a)
,如文中所述。
通过
定义constantly
没有任何违法行为
fun constantly (k,a) = k
它将具有您似乎期望的类型'a * 'b -> 'a
,但不断地称它为#34;#34;然后有点奇怪,因为它不会是一个常数函数。
我确信哈珀迟早会得到它。 ML和Haskell(尤其是Haskell)都大量使用这些函数。