OCaml:使用控制语句保留变量的值

时间:2014-03-06 06:26:02

标签: ocaml

我对OCaml /函数式编程非常陌生,而且我对一些相对简单的其他语言的实现感到困惑。我可以使用任何和所有的帮助。

主要是:在我正在研究的程序中,我根据某个参数递增或递减变量。这是代表我所拥有的东西:

let tot = ref 0 in
for i = 0 to s do
    if test_num > 0 then 
        tot := !tot + other_num
    else
        tot := !tot - other_num
done;;

这显然不是解决这个问题的方法,因为即使永远不会使用else语句,代码的行为就好像每次一样,大概是因为它更接近底层程序?我知道OCaml有非常复杂的模式匹配,但在这个级别的男女同校中我需要访问我已经创建的一些列表,据我所知,我无法从顶级函数访问这些列表没有将它们全部作为参数传递。

我知道我会以错误的方式解决这个问题,但我不知道该如何做到这一点。

连连呢?感谢。

修改 这是一个更简洁的例子:

let ex_list = [1; -2; 3; -4] in
let max_mem = ref 0 in
let mem = ref 0 in
let () = 
    for i = 0 to 3 do
        let transition = List.nth ex_list i in
        if transition > 0 then (
            mem := (!mem + 10);
        ) else 
            mem := (!mem - 1);
        if (!mem > !max_mem) then (max_mem := !mem);
    done;
print_int !max_mem; print_string "\n";
in !mem;

最后,当我打印max_mem时,我得到19,尽管这个值应该是(0 + 10 - 1 + 10 - 1 = 18)。我的数学错误,或问题来自其他地方?

2 个答案:

答案 0 :(得分:2)

您的代码对我来说很好。它作为实际代码没有多大意义,但我认为你只是想展示一个总体布局。它也是以命令式的方式写的,如果可能的话我通常会尽量避免。

OCaml中的if就像在其他语言中一样,在程序的底部附近没有特别之处。 (更确切地说,它的行为类似于C和相关语言的? :三元运算符;即,它是一个表达式。)

您的代码不会返回有用的值;它总是返回()(典型的无趣值,称为“单位”)。

如果我们用常量替换你的自由变量(在这段代码中没有定义),并更改代码以返回一个值,我们可以运行它:

# let s = 8 in
let other_num = 7 in
let test_num = 3 in
let tot = ref 0 in
let () =
    for i = 0 to s do
        if test_num > 0 then
            tot := !tot + other_num
        else
            tot := !tot - other_num
    done
in
!tot;;
- : int = 63
#

如果您正在尝试学习函数样式(即没有可变变量),您可以将此循环编写为递归函数,并使tot成为参数:

# let s = 8 in
let other_num = 7 in
let test_num = 3 in
let rec loop n tot =
    if n > s then 
        tot
    else 
        let tot' =
            if test_num > 0 then tot + other_num else tot - other_num
        in
        loop (n + 1) tot'
in
loop 0 0;;
- : int = 63

如果你给了一个(编辑添加:小:-)你想要解决的自包含问题,可能会更容易提供帮助。

您问题的其他部分不够明确,无法提供任何建议。我可能会指出的一点是,在处理列表时使用模式匹配是完全惯用的。

此外,将事物作为参数传递并没有错。这就是为什么语言被称为“功能” - 你的代码由具有参数的函数组成。

<强>更新

我想写let () = expr1 in expr2而不是expr1; expr2。这只是我养成的一种习惯,抱歉,如果这让人感到困惑。实质是你正在评估第一个表达式只是为了它的副作用(它有类型unit),然后返回第二个表达式的值。

如果您在for之后没有内容,代码将评估为(),正如我所说的那样。由于代码的目的似乎是计算!tot的值,这就是我返回的内容。至少,这可以让你看到OCaml顶级的计算值。

tot'只是另一个变量。如果直接从名为var的变量计算新值,则通常将新值命名为var'。它读作“var prime”。

更新2

您的示例代码工作正常,但它存在使用List.nth遍历列表的问题,这是一个慢(二次)操作。事实上,您的代码自然被视为折叠。以下是您可以用函数式编写它的方法:

# let ex_list = [1; -2; 3; -4] in
let process (tot, maxtot) transition =
    let tot' = if transition > 0 then tot + 10 else tot - 1 in
    (tot', max maxtot tot')
in
List.fold_left process (0, 0) ex_list;;
- : int * int = (18, 19)
#

答案 1 :(得分:0)

除了Jeffrey的回答之外,让我再说一下,这不是你通常会在Ocaml中编写这样的代码的方式,因为它是一种非常低级的命令式方法。功能更强大的版本如下所示:

let high ex_list =
  let deltas = List.map (fun x -> if x > 0 then 10 else -1) ex_list in
  snd (List.fold_left (fun (n, hi) d -> (n+d, max (n+d) hi)) (0, 0) deltas)

let test = high [1; -2; 3; -4]