第一个和第二个flatMap
运作良好。为什么第三个不起作用?
fun flatMap f xs = List.concat(List.map f xs)
fun flatMap f = List.concat o List.map f
val flatMap = (fn mmp => List.concat o mmp) o List.map;
答案 0 :(得分:1)
这是由于称为“值多态性”或“值限制”的规则。根据此规则,如果表达式可能是“扩展的”,则值声明不能创建多态绑定;也就是说,一个值声明只能创建一个多态绑定,前提是它符合严格限制的语法,确保它不能创建引用单元或异常名称。
在您的示例中,由于 (fn mmp => List.concat o mmp) o List.map
调用函数 o
,因此它不是非扩展性的; 您知道 o
不会创建引用单元格或异常名称,但语法无法区分。
所以声明 val flatMap = (fn mmp => List.concat o mmp) o List.map
仍然是允许的,但它不能创建多态绑定:它必须给 flatMap
一个单态类型,例如 (int -> real list) -> int list -> real list
。 (注意:并非标准 ML 的所有实现都可以在所有上下文中推断出所需的类型,因此您可能需要添加显式类型提示。)
存在此限制是为了确保我们不会通过使用一种类型写入引用单元并使用不同类型读取它来隐式地从一种类型转换为另一种类型,或者通过将一种类型包装在多态异常构造函数中并展开它使用不同的类型。例如,下面的程序被值限制禁止,但如果允许,每个程序都会创建一个名为 garbage
的类型为 string
的变量,该变量是从 整数 初始化的17
:
val refCell : 'a option ref =
ref NONE
val () = refCell := SOME 17
val garbage : string =
valOf (! refCell)
val (wrap : 'a -> exn, unwrap : exn -> 'a) =
let
exception EXN of 'a
in
(fn x => EXN x, fn EXN x => x)
end
val garbage : string =
unwrap (wrap 17)
更多信息: