问题描述
let rec subtract_list myl = match myl with
| [] -> 0
| a::rest-> List.fold_right (fun y z -> y-z ) myl 0
我想从列表中减去列表中的元素,但结果不正确
subtract_lst [11; 1; 1; 1] = 8,但是我得到的结果是10。这是怎么了?
解决方法
问题在于fold_right以这种方式工作(https://caml.inria.fr/pub/docs/manual-ocaml/libref/List.html):
List.fold_right f [a1; ...; an] b is f a1 (f a2 (... (f an b) ...)). Not tail-recursive.
所以你有什么:
11 - (1 - (1 - 1))
您可以通过更改代码来解决它:
let subtract_list myl =
match myl with
| [] -> 0
| a::rest -> List.fold_left (fun acc e -> acc - e) a rest
;;
或:
let subtract_list myl = if myl = [] then 0 else
List.fold_left (fun acc e -> acc - e) (List.hd myl) (List.tl myl)
;;
,
您遇到的问题是,尽管您的列表包含同质值,但含义并不相同。
对于您来说,使用明确的类型(例如:
type t =
( int (* The substracted *)
* int list ) (* The subtractors *)
允许您编写此功能:
let subtract_list
: t -> int
= function
| (i,[]) -> i
| (i,tl) -> List.fold_left (-) i tl
有了列表并遵循相同的模式,您可以编写此函数:
let subtract_list
: int list -> int
= function
| [] -> 0 (* Empty list,nothing to do *)
| i::[] -> i (* Case where you have nothing to substract *)
| i::tl -> List.fold_left (-) i tl
注意:我用短路来减去元素List.fold_left (-) i tl
与List.fold_left (fun x y -> x - y) i tl
相同