avoiding cost of (++)

John Hughes rjmh@cs.chalmers.se
Fri, 17 Jan 2003 10:11:09 +0100 (MET)


On Thu, 16 Jan 2003, Hal Daume III wrote:

> I have a function which behaves like map, except instead of applying the
> given function to, say, the element at position 5, it applies it to the
> entire list *without* the element at position 5.  An implementation looks
> like:
>
> > 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 (++).
>

I don't think this can be sped up appreciably without avoiding the
construction of the lists pre++xs. To accomplish that, I would change the
type of mapWithout, as follows:

mapPrePost :: ([a] -> [a] -> b) -> [a] -> [b]
mapPrePost f = mapWith' []
  where mapWith' pre [] = []
	mapWith' pre (x:xs) = f pre xs : mapWith' (x:pre) xs

OK, you have to change the functions passed as f, and if f REALLY needs to
compute pre++xs then there is no gain, but I'm betting that in many cases
f has some property that enables

	f' pre xs = f (pre++xs)

to be computed by a more efficient method.

John