Я не думаю, что я единственный, кто многому научился (борется с) решением Daniel CPS. Попытка выяснить это помогла мне изменить несколько потенциально (для начинающих) неоднозначных ссылок в списке, например, так:
let partitionWhileCps cond l1 =
let rec aux f l2 =
match l2 with
| h::t when cond h -> aux (fun (acc, l3) -> f (h::acc, l3)) t
| l4 -> f ([], l4)
aux id l1
(Обратите внимание, что "[]" в совпадении l4 является начальным значением acc.) Мне нравится это решение, потому что он чувствует себя менее хитроумно, не используя List.rev, сверляя до конца первого списка и создавая второй список задом наперед. Я думаю, что другой основной способ избежать .rev будет использовать хвостовую рекурсию с операцией cons. Некоторые языки оптимизируют «противодействие хвостовой рекурсии» так же, как и правильную хвостовую рекурсию (но Дон Сайм сказал, что это не произойдет в F #).
Так что это не является хвостовой рекурсивной безопасностью в F #, но это делает мой ответ ответом и избегает List.rev (это уродливо иметь доступ к двум элементам кортежа и было бы более подходящим параллельно подходу cps, иначе Я думаю, как если бы мы только вернули первый список):
let partitionWhileTrmc cond l1 =
let rec aux acc l2 =
match l2 with
| h::t when cond h -> ( h::fst(aux acc t), snd(aux acc t))
| l3 -> (acc, l3)
aux [] l1