以下是我要实施的内容
功能方式
let sum l = List.fold_left (fun s x -> s+x) 0 l
势在必行
let sum l =
let sum = ref 0 in
List.iter (fun x -> sum := !sum +x) l;
!sum
还有更好/更快的方法吗?
我之所以这样问是因为书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>
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.
答案 0 :(得分:10)
这稍微凉爽一点;)
let sum l = List.fold_left (+) 0 l;;
要查看效果:
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"
;;
给予
$ 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
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!
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!
任何人都知道为什么?
答案 1 :(得分:3)
使用电池:
let sum = BatList.reduce (+)
(实际上,电池已经具有BatList.sum功能,它可以完全按照您的要求进行操作 - 因此无需编写它:)
答案 2 :(得分:1)
作者想到的替代方案可能是手动编写折叠:
let low_level_sum list =
let rec loop sum = function
| [] -> sum
| x::xs -> loop (sum + x) xs in
loop 0 list
这是丑陋且低级别的,除非您有具体的性能问题,否则您应该更喜欢List.fold_left (+) 0
。 (甚至可能在那时 - OCaml编译器的递归函数内联正在进行中,并且可能没有性能优势。)