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

OCaml:使用控制语句保留变量的值,ocaml,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;;

我对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有非常复杂的模式匹配,但在这个coed级别中,我需要访问我已经创建的一些列表,而且,据我所知,如果不将它们全部作为参数传递,我无法从顶级函数访问这些列表

我知道我走错了方向,但我不知道如何惯用这个方法

建议?谢谢

编辑 下面是一个更简洁的示例:

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)。我算错了,还是问题来自其他地方?

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

如果OCaml中的
与其他语言中的
一样,那么接近程序的底部就没有什么特别的地方了。(更准确地说,它的作用类似于C和相关语言中的
?:
三元运算符;也就是说,它是一个表达式。)

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

如果我们用常量替换您的自由变量(代码中未定义的变量),并更改代码以返回值,我们可以运行它:

# 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
如果您提供了一个(编辑为添加:small:-)您试图解决的自包含问题,那么可能会更容易提供帮助

你问题的其他部分不够清楚,无法给出任何建议。我要指出的一点是,在处理列表时使用模式匹配是完全惯用的

另外,将事物作为参数传递也没有什么错。这就是为什么这种语言被称为“functional”——您的代码由函数组成,函数具有参数

更新

我喜欢在expr2中编写
let()=expr1,而不是
expr1;expr2
。这只是我养成的习惯,如果让人困惑的话,对不起。本质上,您只是在评估第一个表达式的副作用(它具有type
unit
),然后返回第二个表达式的值

如果在
之后没有任何内容,那么正如我所说,代码将计算为
()
。因为代码的目的似乎是计算
的值!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)
#

除了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]

谢谢,这很有帮助。为了简洁起见,我没有包含全部代码,但我会在下面的评论中这样做。关于你的回答,我有几个问题:
let()=
的意义是什么。。。在循环之前,和
in!tot之后是什么?我知道你必须做
!tot
获取引用的内容,但是在末尾调用变量有什么作用呢?另外,在递归函数中,
tot'
,相对于
tot
,它的含义是什么?(我将用这些新信息编辑我的答案;这些注释不适用于来回的问题。)此外,我意识到我用我的代码而不是我自己的代码编辑了你的答案。诚实的错误。(我拒绝了编辑…不确定编辑之后会发生什么,我不经常这样做。)最好有一个小的自包含的示例。查看大量的代码是很困难的,它没有一个仔细的小示例那么有用。这一切都非常有用。非常感谢。我的代码目前正在运行,因此如果遇到任何其他问题,我将返回到此状态。的最大值为!梅姆今年19岁。最终值为18。我看一点问题都没有。循环4次结束时的值为10、9、19、18。(作为旁白,如果这是你问题的本质,这是一个很好的例子。)