Ну, вы можете сделать его хвостовым рекурсивным, но тогда вы должны полностью изменить список. Вы не хотели бы свернуть это, так как это может выйти из рекурсивного цикла в любое время. Я провел небольшое тестирование, и перевернуть список - это больше, чем восполнить хвостовая рекурсия.
// 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.
// 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]