avoiding cost of (++)
Christian Sievers
sievers@math2.nat.tu-bs.de
Fri, 17 Jan 2003 16:59:26 +0100
Hal Daume III asked:
> > mapWithout :: ([a] -> b) -> [a] -> [b]
> > mapWithout f = mapWith' []
> > where mapWith' pre [] = []
> > mapWith' pre (x:xs) = f (pre ++ xs) : mapWith' (x:pre) xs
>
> Unfortunately, this is very slow, due to the overhead of (++).
>
> Any way I could speed this up would be great. Note that order doesn't
> matter to 'f', but I do need that the order in which the elements of the
> list are processed be the same as in map.
If f is associative, i.e. f (l1++l2) == f [f l1, f l2]
(this forces a=b), you can do
mapWithout :: ([a] -> a) -> [a] -> [a]
mapWithout f l = let n = f [] -- neutral element
b x y = f [x,y] -- binary version
sl = scanl b n l
sr = scanr b n l
in zipWith b sl (tail sr)
You'll probably rather use
mapWithout' (a->a->a) -> a -> [a] -> [a]
mapWithout' bin_op neutral l = ...
If f is not defined for empty lists, you can combine (with a bit more work)
the results of scanl1 and scanr1.
HTH
Christian Sievers