我知道如何在OCaml中使用关键字in
。我的问题是编译器按哪个顺序执行表达式。
例如,让我们采用以下代码:
let v = expr1 in expr2
编译器首先查看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
此代码如何工作?
我的意思是,当我们有递归调用some_function q
时,程序是否直接进入in
块并应用其他递归调用some_function s
?
答案 0 :(得分:6)
当程序显示let v = expr1 in expr2
时,OCaml首先评估expr1
,然后在其中expr2
与该值关联的环境中开始评估v
。是expr1
的结果。
这种评估策略call-by-value并非唯一可行的方法,而是OCaml所采用的策略。
现在让我们考虑一下代码段:
let rec some_function = function ...
in
let s = (*some list*)
some_function s
程序包含上面的代码段时,将执行以下步骤:
function ...
被评估。此步骤很短,因为评估function ...
块并不意味着会评估...
内部的代码。相反,对function ...
求值的结果是一个闭包(忽略了适用于您的示例但并非一般情况下的优化)。(*some list*)
表示的代码是在some_function
绑定到上述闭包的环境中进行评估的。some_function s
绑定到闭包且some_function
绑定到s
的计算结果的环境中计算表达式(*some list*)
。在这种环境下,此评估成功,并且应用了闭包,这意味着现在将执行定义了some_function
的代码(在已提供参数的环境中)。闭包由未评估的代码和部分环境组成。仅需要为参数添加附加绑定来扩展环境,以便包含评估代码所需的所有内容。另一方面,只要未提供参数,就无法开始求值,因为函数的主体引用了参数。
some_function
是递归的事实不会改变一般方案。这仅意味着在评估闭包的主体时,环境还包含将相同的some_function
与闭包关联的绑定,因此对主体内部的some_closure
的调用将以与处理闭包相同的方式处理。会在体外。