OCaml 中的代数处理程序可以分离并放入不同的模块中,然后嵌套在其他文件中吗?
例如,假设您在名为
program.ml
的文件中有一个程序,该程序使用用户定义的函数 put: int -> unit
来修改变量 x
。在这种情况下,存在效果 Put_found: int -> unit Effect.t
并且 put
定义为
put n = x:= n; perform(Put_found n)
示例程序如下所示:
put(5);put(0)
。
还有两个编译单元
Handler1
和Handler2
,每个都有各自的ml和mli文件。前者包含一个函数 run_h1
,当给定示例程序作为输入时,处理程序通过打印传递给它的整数来作用于效果 Put_found
。然后,它引发另一个效果Report_p
,该效果将传递给第二个处理程序。 run_h1
返回类型为 unit -> unit
的函数,如下所示:
let run_h1 () = fun () -> match_with Program.comp () {
effc = (fun (type c) (eff: c Effect.t) ->
match eff with
| Put_found s -> Some (fun (k : (c,_) continuation) ->
report_p(s); continue k ())
| _ -> None
);
}
第二个效果,
Report_p
类型的int -> unit Effect.t
,将由Handler2
中的函数处理,这样如果传递的整数为负数,则会在屏幕上打印一条错误消息。
run_h2
是以下函数:
let run_h2 inst x = match_with inst x
{
effc = (fun (type b) (eff: b Effect.t) ->
match eff with
| Report n -> Some (fun (k: (b,_) continuation) ->
if n = (-1) then printf "Put with value -1 encountered.\n" else printf "Put found with allowed value.\n"; continue k ())
| _ -> None
);
exnc = raise;
retc = fun x-> x
}
在另一个文件
run_handlers.ml
中,我使用了上面提到的编译单元,如下所示:
let run_handlers () = Handler2.run_h2(Handler1.run_h1 ()) ()
当最初在同一个文件中找到程序和效果并且处理程序嵌套在同一个文件中时,程序运行良好。这是它的样子:
程序看起来像这样:
let run_h2 () =
let comp () = put(5); put(6); put(-1); put(100) in
let run_h1 () = match_with comp ()
{ effc = (fun (type c) (eff: c Effect.t) ->
match eff with
| Put_found s -> Some (fun (k: (c,_) continuation) ->
report_p(s); continue k ())
| _ -> None
);
exnc = raise;
retc = fun x-> x
} in
match_with run_h1 () {
effc = (fun (type b) (eff: b Effect.t) ->
match eff with
| Report n -> Some (fun (k: (b,_) continuation) ->
if n = (-1) then printf "Put with value -1 encountered.\n" else printf "Put found with value: %d\n" (n); continue k ())
| _ -> None
);
exnc = raise;
retc = fun x-> x
}
现在,我正在尝试将其模块化,但是在应该执行效果的第一个实例上抛出了
Stdlib.Effect.Unhandled
异常。
问题在于,效果构造函数没有在
Handler1
和 Handler2
之间共享,因此,就好像构造函数不同,这就是处理程序无法识别效果的原因。一旦我将效果放入一个文件中,然后在编译单元之间共享该文件,问题就解决了。