我知道如何in在OCaml中使用关键字.我的问题是编译器执行表达式的顺序.
例如,让我们采用以下代码:
let v = expr1 in expr2
Run Code Online (Sandbox Code Playgroud)
编译器首先查看expr2,然后当它v出现expr2时替换v为expr1?或者首先,它评估expr1然后应用expr2?
你可能想知道我为什么要问这个奇怪的问题.这是因为我不明白以下代码的工作原理:
let rec some_function = function
| [] -> ()
| t::q when (*here put a condition*) -> some_function q
| t::q -> (*some operations here*); some_function q
in
let s = (*some list*)
some_function s
Run Code Online (Sandbox Code Playgroud)
这段代码是如何工作的?我的意思是当我们有递归调用some_function q然后程序直接进入in块并应用其他递归调用some_function s?
当程序说let v = expr1 in expr2,OCaml首先评估expr1,然后开始评估expr2在一个环境中,该环境v与作为结果获得的值相关联expr1.
这种评估策略,按值调用,并不是唯一可行的,但它是OCaml使用的策略.
现在让我们考虑一下片段:
let rec some_function = function ...
in
let s = (*some list*)
some_function s
Run Code Online (Sandbox Code Playgroud)
当程序包含上面的代码段时,会执行以下步骤:
function ...被评估.此步骤很短,因为评估function ...块并不意味着...评估内部代码.相反,评估的结果function ...是一个闭包(忘记在你的例子中适用但不是一般的优化).(*some list*)在一个some_function绑定到上面讨论的闭包的环境中进行评估.some_function s在some_function绑定到闭包的环境中进行求值,并s绑定到求值的结果(*some list*).在此环境中,此评估成功并应用闭包,这意味着some_function现在将执行定义的代码(在已提供其参数的环境中).闭包由未评估的代码和部分环境组成.只需要为参数添加额外的绑定来扩充环境,以便包含评估代码所需的所有内容.另一方面,只要没有提供参数,评估就无法开始,因为函数的主体引用了参数.
some_function递归的事实不会改变一般方案.它只意味着当对闭包的主体进行评估时,环境还包含一个将闭合体与闭合相关联的绑定some_function,这样some_closure对身体内部的调用就像处理体外一样.