Re-implementing List.map in OCaml/F# with correct side effect order?

断了今生、忘了曾经 提交于 2019-12-04 06:22:40

So when you have an implementation of map like this:

let rec map f = function
  | [] -> []
  | a::l -> f a :: map f l

none of the function applications (f a) within the map calls are guaranteed to be evaluated sequentially in the order you'd expect. So when you try this:

map print_int [1;2;3]

you get the output

321- : unit list = [(); (); ()]

since by the time those function applications weren't executed in a specific order.

Now when you implement the map like this:

let rec map f = function
  | [] -> []
  | a::l -> let r = f a in r :: map f l

you're forcing the function applications to be executed in the order you're expecting because you explicitly make a call to evaluate let r = f a.

So now when you try:

map print_int [1;2;3]

you will get

123- : unit list = [(); (); ()]

because you've explicitly made an effort to evaluate the function applications in order.

The point is that the order of function application in OCaml is unspecified, not that it will be in some specific undesired order.

When evaluating this expression:

project head :: map project tail

OCaml is allowed to evaluate project head first or it can evaluate map project tail first. Which one it chooses to do is unspecified. (In theory it would probably be admissible for the order to be different for different calls.) Since you want a specified order, you need to use the form with let.

The fact that the order is unspecified is documented in Section 6.7 of the OCaml manual. See the section Function application:

The order in which the expressions expr, argument1, …, argumentn are evaluated is not specified.

(The claim that the evaluation order is unspecified isn't something you can test. No number of cases of a particular order prove that that order is always going to be chosen.)

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!