Sml 顶级无点标准毫升

Sml 顶级无点标准毫升,sml,pointfree,Sml,Pointfree,第一个和第二个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; 这是由于一个称为“值多态性”或“值限制”的规则造成的。根据此规则,如果表达式可能是“可扩展的”,则值声明不能创建多态绑定;也就是说,如果值声明符合

第一个和第二个
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;

这是由于一个称为“值多态性”或“值限制”的规则造成的。根据此规则,如果表达式可能是“可扩展的”,则值声明不能创建多态绑定;也就是说,如果值声明符合高度受限的语法,确保它不能创建ref单元格或异常名称,那么它只能创建多态绑定

在您的示例中,由于
(fn mmp=>List.concat o mmp)o List.map
调用函数
o
,因此它不是非扩展的;您知道
o
不会创建ref单元格或异常名称,但语法无法区分这一点

因此,仍然允许声明
val flatMap=(fn mmp=>List.concat o mmp)o List.map
,但它不能创建多态绑定:它必须给
flatMap
一个单态类型,例如
(int->real List)->int List->real List
。(注意:并非所有标准ML实现都能在所有上下文中推断出所需的类型,因此您可能需要添加显式类型提示。)

存在此限制是为了确保我们不会通过使用一种类型写入ref单元格并使用其他类型从中读取,或者通过在多态异常构造函数中包装一种类型并使用其他类型将其展开,从而隐式地从一种类型强制转换到另一种类型。例如,值限制禁止以下程序,但如果允许,每个程序都将创建一个名为
垃圾
的变量,类型为
string
,该变量由整数
17
初始化:

val refCell : 'a option ref =
  ref NONE

val () = refCell := SOME 17

val garbage : string =
  valOf (! refCell)
有关更多信息:

  • 。(标准ML'90有一个不同版本的规则,这是更为宽松的-它会允许您的程序-但认为“有些微妙”,在某些情况下“令人不快”,因此它在标准ML'97中被替换。)
  • 以下各节:
    • §4.7“非扩展表达式”,第21页,定义了哪些表达式被视为“非扩展”(因此可用于多态值声明)
    • §4.8“关闭”,第21-22页,定义了使绑定多态的操作;如果表达式可能是可扩展的,则此操作通过防止绑定变为多态来强制值限制
    • 推理规则(15),第26页,使用上述操作;另见第27页的评论
    • 关于推断规则(20)的注释,第27页,解释了为什么上述操作不适用于异常声明。(从技术上讲,这与值限制有一定的区别;但如果没有这一点,值限制将毫无用处。)
    • §G.4“价值多态性”,第105-106页,讨论了与标准ML'90的这种变化

由于语言规范中有一条称为“值限制”的规则:
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)