末尾再帰にすることはできますが、リストを逆にする必要があります。いつでも再帰ループから抜け出すことができるので、折りたたむ必要はありません。私は少しテストを行いましたが、リストを逆にすることは末尾再帰で補う以上のものです。
// 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)
ブライアンに似たバージョンで、末尾再帰であり、単一の値の述語を取ります。
// 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のようなfalseを返すとすぐに要素の取得を停止するという点で、ライブラリ関数パーティションとは異なります。
// 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]