我对OCaml的评估模型不太熟悉。如果有人能解释为什么这两行代码会产生不同的结果,我将不胜感激:
List.iter (fun s -> Printf.printf "%s" s) ["a"; "b"; "c"];; (* prints abc *)
List.iter (fun f -> f) [Printf.printf "a"; Printf.printf "b"; Printf.printf "c"];; (* prints cba *)
答案 0 :(得分:4)
OCaml是一种严格的函数式编程语言:函数的参数在传递给函数之前被评估为值(并且表达式中的副作用发生)(并且函数内部的任何副作用都可能发生)。
为了理解你的第二个例子,最好稍微去掉它:
List.cons
(Printf.printf "a")
(List.cons (Printf.printf "b") (List.cons (Printf.printf "c") []))
当一个函数同时传递多个参数时 - 就像这里所有List.cons
函数的情况一样 - 参数的评估顺序是未指定的。例如,字节码和本机编译器之间的顺序可能不同。在这里,您使用的编译器决定首先评估第一个List.cons
的第二个参数。在这样做时,它遇到了一个应用程序(第二个List.cons
)
...
在评估上一个List.cons
的参数时,它打印了c
。结果是()
,这允许它构建值[()]
。这个论点准备好了,它现在评估了第二个List.cons
的另一个参数。这使它打印b
。最后,由于第一个[();()]
的参数List.cons
已准备就绪,因此它评估了另一个参数。这使它打印a
。
答案 1 :(得分:1)
正如Pascal Cuoq已经回答了你的问题,让我澄清一下我从问题标题中可能产生的误解:你的代码中没有任何一个功能列表。
在第一行中有一个字符串列表["a";"b";"c"]
。
在第二行中,您有一个包含Printf.printf "a"
等元素的列表,这些元素是函数应用程序。它们的结果类型是unit
,也不是函数类型。 (事实上,列表只是[();();()]
。)
功能列表的一个例子是
[(fun () -> print_string "a"); (fun () -> print_string "b"); (fun () -> ())]