另一個拿這個問題。
let first_last xs =
let rec last_non_empty = function
| [x] -> x
| _ :: xs' -> last_non_empty xs'
| [] -> failwith "first_last: impossible case!"
in
match xs with
| [] -> failwith "first_last"
| x::_ -> (x, last_non_empty xs)
該實現方式的一些性質: (1)它符合規範'a list -> 'a * 'a
:
utop > #typeof "first_last";;
val first_last : 'a list -> 'a * 'a
(2)它爲單列表:first_last [x] = (x,x)
:
utop> first_last [1];;
- : int * int = (1, 1) utop> first_last ["str"];;
- : bytes * bytes = ("str", "str")
(3 )它是尾遞歸的(因此,對於足夠大的列表,它不會導致堆棧溢出):
utop > first_last (Array.to_list (Array.init 1000000 (fun x -> x+1)));;
- : int * int = (1, 1000000)
(4)它只遍歷輸入列表一次; (5)它避免了在遞歸階梯中創建新列表; (6)避免污染名稱空間(價格不允許重用像last
這樣的函數)。
而另一個相當簡單的變型,從第一原則(我是想說明在SICP書的精神「如意算盤」):
(* Not tail-recursive, might result in stack overflow *)
let rec first_last = function
| [] -> failwith "first_last"
| [x] -> (x,x)
| x :: xs -> (x, snd (first_last xs))
'first_last [x]'應該返回'x,x' – ivg