在标准 ML 中声明相互依赖的值和函数
Declaring interdependent values and functions in Standard ML
如何在标准 ML 中定义相互依赖的函数和值?
以下程序:
val cmds = [("help", cmd_help)];
fun cmd_help () = List.app (fn cmd => print (#1 cmd ^ "\n")) cmds;
cmd_help ();
不编译:
$ mlton example.sml
Error: example.sml 1.22-1.29.
Undefined variable: cmd_help.
是否可以定义 cmds
和 cmd_help
,使它们彼此了解并作为顶级定义暴露给程序的其余部分?
有趣的问题,最明显的方法是使 cmds
成为单一函数,然后在 cmd_help
中调用它,就像一对普通的递归函数一样。
fun cmds () = [("help", cmd_help)]
and cmd_help () = List.app (fn cmd => print ((#1 cmd) ^ "\n")) (cmds ());
cmd_help ();
人们会期望您可以扭转这种情况,将 cmds_help
视为一个值。事实上,语法甚至似乎可以解析。
val a = ()
and b = fn () => ()
但是,当您将相互递归添加到作品中时,它实际上并没有编译(我尝试了以下 MLton 和 smlnj ).手动声明类型,因为推理不是特别好。
val cmds_v : (string * (unit -> unit)) list = [("help", cmd_help_v)]
and cmd_help_v : unit -> unit = fn () => List.app (fn (cmd: string * (unit -> unit)) => print ((#1 cmd) ^ "\n")) (cmds_v);
最后一个案例的结果是:
Error: unbound variable or constructor: cmds_v
Error: unbound variable or constructor: cmd_help_v
所以现在的问题是,为什么这行不通
如果我们查看第 42 页的 Value Bindings 部分
The Definition of Standard ML (Revised)
在脚注 25 中它说
(25) When the option is present we have Dom VE ∩ Dom VE′ = ∅ by the syntactic restrictions.
因此,虽然函数的 and
允许相互递归,但值的 and
允许确保值环境不相交。
唉,如果不将值提升为函数,我不知道该怎么做。
我认为最好的解决方案是将函数包装在 ref
访问中,如下所示:
val cmd_help_ref : (unit -> unit) ref
= ref (fn _ => raise Fail "cmd_help not bound");
fun cmd_help () = !cmd_help_ref ();
val cmds = [("help", cmd_help)];
cmd_help_ref := fn () => List.app (fn cmd => print (#1 cmd ^ "\n")) cmds;
cmd_help ();
如何在标准 ML 中定义相互依赖的函数和值?
以下程序:
val cmds = [("help", cmd_help)];
fun cmd_help () = List.app (fn cmd => print (#1 cmd ^ "\n")) cmds;
cmd_help ();
不编译:
$ mlton example.sml
Error: example.sml 1.22-1.29.
Undefined variable: cmd_help.
是否可以定义 cmds
和 cmd_help
,使它们彼此了解并作为顶级定义暴露给程序的其余部分?
有趣的问题,最明显的方法是使 cmds
成为单一函数,然后在 cmd_help
中调用它,就像一对普通的递归函数一样。
fun cmds () = [("help", cmd_help)]
and cmd_help () = List.app (fn cmd => print ((#1 cmd) ^ "\n")) (cmds ());
cmd_help ();
人们会期望您可以扭转这种情况,将 cmds_help
视为一个值。事实上,语法甚至似乎可以解析。
val a = ()
and b = fn () => ()
但是,当您将相互递归添加到作品中时,它实际上并没有编译(我尝试了以下 MLton 和 smlnj ).手动声明类型,因为推理不是特别好。
val cmds_v : (string * (unit -> unit)) list = [("help", cmd_help_v)]
and cmd_help_v : unit -> unit = fn () => List.app (fn (cmd: string * (unit -> unit)) => print ((#1 cmd) ^ "\n")) (cmds_v);
最后一个案例的结果是:
Error: unbound variable or constructor: cmds_v
Error: unbound variable or constructor: cmd_help_v
所以现在的问题是,为什么这行不通 如果我们查看第 42 页的 Value Bindings 部分 The Definition of Standard ML (Revised) 在脚注 25 中它说
(25) When the option is present we have Dom VE ∩ Dom VE′ = ∅ by the syntactic restrictions.
因此,虽然函数的 and
允许相互递归,但值的 and
允许确保值环境不相交。
唉,如果不将值提升为函数,我不知道该怎么做。
我认为最好的解决方案是将函数包装在 ref
访问中,如下所示:
val cmd_help_ref : (unit -> unit) ref
= ref (fn _ => raise Fail "cmd_help not bound");
fun cmd_help () = !cmd_help_ref ();
val cmds = [("help", cmd_help)];
cmd_help_ref := fn () => List.app (fn cmd => print (#1 cmd ^ "\n")) cmds;
cmd_help ();