ocaml - 为什么 "currying"要求很重要?

标签 ocaml currying

我正在读这个OCaml walking through幻灯片,我在这里发现了一个有趣的问题:

enter image description here

看来 oops 函数会产生一个编译错误:

the type of this expression contains type variables that cannot be generalized

我不知道原因,所以我在我的 Mac 上使用 OCaml 版本 4.01.0 快速对该函数进行了一些测试,令我惊讶的是,我在解释这段代码时没有看到任何错误

我不知道为什么幻灯片声称这是一个错误,因为柯里化(Currying),我不能重新创建这个错误...

谁能帮帮我?

最佳答案

编译器提示这个错误,但顶层没有。

$ cat ungen.ml
open List
let oops = fold_left (fun a _ -> a + 1) 0
$ ocamlc -c ungen.ml
File "ungen.ml", line 2, characters 11-41:
Error: The type of this expression, '_a list -> int,
       contains type variables that cannot be generalized

问题仍然存在于顶层;如果你尝试使用 oops 你会看到它计算两个不同类型列表的长度:

$ ocaml
        OCaml version 4.01.0

# open List;;
# let oops = fold_left (fun a _ -> a + 1) 0;;
val oops : '_a list -> int = <fun>
# oops [1;2;3;4];;
- : int = 4
# oops ['a';'b';'c'];;
Error: This expression has type char but an expression was expected of type
         int
# 

请注意,如果您使用 oops只有一种类型的列表(不是零或两个),没有错误。如果您使用 oops,编译器可能会报错(导出的符号)零次因为它可以看到整个模块并且知道如何 oops用来。顶层不能提示零使用,因为它永远不知道你接下来会输入什么。

更新

抱歉,我应该更多地说明实际错误是什么(在我理解的层面上)。在我看来,这与柯里化(Currying)没什么关系。

这就是臭名昭著的“值(value)限制”。值限制的简短描述如下:有些表达式不能安全地泛化。也就是说,您不能使它们成为多态的,从而允许它们与所有类型一起使用。最简单的例子是这样的:

let mylist = ref []

如果你允许mylist具有类型 'a list ref ,然后您可以在其中存储所有不同类型的列表,这是不安全的。

但是,这可以安全地概括为:

let mylist2 = []

泛化没有问题mylist2到类型 'a list .

在像 OCaml 这样的现代 ML 衍生产品中,对泛化的限制已经减少到或多或少的简单规则。可以概括“值”(如 [] )。不是值的表达式(如 ref [] )不能被泛化。

表达式:

fold_left (fun a _ -> a + 1) 0

不是一个值。这是一个函数应用程序,具有与 ref [] 相同的粗略形式。 .这(显然)是 oops 的定义以上。

另一方面,表达式:

fun xs -> fold_left (fun a _ -> a + 1) 0 xs

一个值;这是一个 lambda 。所以可以泛化。这(在展开一个方便的语法缩写之后)是 len 的定义。多于。这就是为什么 len适用于所有列表,但 oops没那么有用。

值和非值之间的区别是语法上的;也就是说,它可以通过局部查看表达式的形式来确定。您无需了解有关表达式的类型或含义的任何信息即可做出决定。

在当前形式中使用值限制的一个论点是,在大多数情况下,您可以通过以 len 的形式定义函数来恢复所需的泛化(即多态性)。而不是 oops 的形式.这种简单的转换称为“eta 扩展”。

eta 扩展仅更改语法而不更改函数的含义这一事实表明值限制只是一个近似值。也就是说,它禁止泛化一些可以安全泛化的表达式。但它既好又简单,并且对实际程序中出现的情况没有太多限制。

从 OCaml 3.07 开始,OCaml 的值限制在基本 ML 的基础上得到了改进,因为它允许在更多情况下进行泛化。您可以在这里阅读:J. Garrigue, Relaxing the Value Restriction .本文还包含对值(value)限制及其历史的精彩总结。

关于ocaml - 为什么 "currying"要求很重要?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23178233/

相关文章:

快速函数 () -> (Int) -> 字符串

list - Currying:追加两个列表

c# - 如何支持名义类型语言的结构类型?

ocaml - 在 OCaml 中管理 GPU 内存

module - 在 OCaml 中哪里放置共享实用程序模块?

scala - 带有 curry 功能的奇怪东西

c++ - 如何柯里化(Currying)对象上的方法以将其作为 C 风格回调传递?

mysql - OCaml 的数据库绑定(bind)?

list - 笛卡尔积类型错误

scala - 如何在scala中使用带有 curry 函数的命名参数