好吧,您可以使其尾递归,但随后您必须反转列表。您不想折叠它,因为它可以随时退出递归循环。我做了一些测试,并且反转列表不仅仅是尾递归所弥补的。
// val pred : ('a list -> bool)
let split pred xs =
let rec split' l xs ys =
match xs with
| [] -> [], ys
| x::xs -> if pred (x::l) then (split' (x::l) xs (x::ys)) else x::xs, ys
let last, res = split' [] xs []
(res |> List.rev, last)
一个类似于 Brian 的版本,它是尾递归的并且采用单个值谓词。
// val pred : ('a -> bool)
let split pred xs =
let rec split' xs ys =
match xs with
| [] -> [], ys
| x::xs -> if pred x then (split' xs (x::ys)) else (x::xs), ys
let last, res = split' xs []
(res |> List.rev, last)
这与库函数分区的不同之处在于,一旦谓词返回类似于 Seq.takeWhile 的错误类型,它就会停止获取元素。
// library function
let x, y = List.partition (fun x -> x < 5) li
printfn "%A" x // [1; 3; 2; 4]
printfn "%A" y // [5; 7; 6; 8]
let x, y = split (fun x -> x < 5) li
printfn "%A" x // [1; 3]
printfn "%A" y // [5; 7; 2; 4; 6; 8]