Useful generic functions are usually the result of composing useful generic functions; the fact that these are easy to write is, however, not an excuse for not having them in a rich prelude. Given a total function for splitting a list at a given point:
let rec split_at n = function | [] -> [], [] | l when n == 0 -> [], l | x :: xs -> let l, r = split_at (pred n) xs in x :: l, r
and the anamorphism on lists, the basic functional iteration scheme giving the list of results:
let rec unfold f e = match f e with | None -> [] | Some (x, e') -> x :: unfold f e'
then splitting a list into chunks just requires some assembly:
let chunks n = unfold (fun l -> match split_at n l with [], [] -> None | p -> Some p)
As another example, suppose we need a Procrustean function fit
that truncates a list or pads it with a value to a given length. Given an way to build an infinite list:
let all x = let rec l = x :: l in l
the desired function is just:
let fit n e l = fst (split_at n (l @ all e))
The only good thing about the paucity of Pervasives
is that it forces one to practice often this kind of finger exercises. At least they are pretty.
Of course, take == fst % split_at, and similarly for drop == snd % split_at.
ReplyDelete