在OCaml中总结一个列表最常用(或最快)的方法是什么?

Jac*_*ale 5 ocaml

这是我要实现的

功能方式

let sum l = List.fold_left (fun s x -> s+x) 0 l
Run Code Online (Sandbox Code Playgroud)

势在必行

let sum l =
  let sum = ref 0 in
  List.iter (fun x -> sum := !sum +x) l;
  !sum
Run Code Online (Sandbox Code Playgroud)

还有更好/更快的方法吗?

我问这个是因为Real World OCaml这本书说:

# let sum list =
    let sum = ref 0 in
    List.iter list ~f:(fun x -> sum := !sum + x);
    !sum
  ;;
val sum : int list -> int = <fun>
Run Code Online (Sandbox Code Playgroud)

This isn't the most idiomatic (or the fastest) way to sum up a list, but it shows how you can use a ref in place of a mutable variable.

sea*_*mcl 10

这稍微凉爽;)

let sum l = List.fold_left (+) 0 l;;
Run Code Online (Sandbox Code Playgroud)

要看性能:

open Printf

let sum1 l = List.fold_left (fun s x -> s+x) 0 l;;
let sum2 l = List.fold_left (+) 0 l;;
let sum3 = List.fold_left (+) 0;;

let rec make_list x acc = function
| 0 -> acc
| n -> make_list x (x :: acc) (n-1)

let l = make_list 1 [] 50000000;;

let _ = match Sys.argv.(1) with
| "1" -> printf "%d\n" (sum1 l)
| "2" -> printf "%d\n" (sum2 l)
| "3" -> printf "%d\n" (sum3 l)
| _ -> printf "Bad arg\n"
;;
Run Code Online (Sandbox Code Playgroud)

给予

$ ocamlc foo.ml
$ time ./a.out 1
50000000

real    0m8.204s
user    0m7.211s
sys 0m0.848s
$ time ./a.out 2
time ./a.out 3
50000000

real    0m8.226s
user    0m7.325s
sys 0m0.818s
$ 50000000

real    0m8.472s
user    0m7.561s
sys 0m0.837s
Run Code Online (Sandbox Code Playgroud)

sum1和sum2具有完全相同的字节码:

    branch L2
    restart
L3: grab 1
    acc 1
    push
    acc 1
    addint
    return 2
L1: acc 0
    push
    const 0
    push
    closure L3, 0
    push
    getglobal List!
    getfield 14
    appterm 3, 4
L2: closure L1, 0
    push
    acc 0
    makeblock 1, 0
    pop 1
    setglobal Foo1!
Run Code Online (Sandbox Code Playgroud)

sum3具有较小的字节码但速度较慢

    branch L2
    restart
L1: grab 1
    acc 1
    push
    acc 1
    addint
    return 2
L2: const 0
    push
    closure L1, 0
    push
    getglobal List!
    getfield 14
    apply 2
    push
    acc 0
    makeblock 1, 0
    pop 1
    setglobal Foo3!
Run Code Online (Sandbox Code Playgroud)

谁知道为什么?

  • let sum = List.fold_left(+)0 ;; (11认同)