avoiding cost of (++)

John van Groningen johnvg@cs.kun.nl
Fri, 17 Jan 2003 14:27:51 +0100


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 (++).
>
>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.

The following version is probably faster:

mapWithout f [] = []
mapWithout f l = map_without l [] []
 	where
	   map_without [e] t t2
		    = f t:t2
	   map_without [e1,e2] t t2
		    = f (e2:t):f (e1:t):t2
	   map_without l t t2
		    = map_without l1 (l2++t) (map_without l2 (l1++t) t2)
		    where
			     (l1,l2) = splitAt (length l `div` 2) l

Regards,

John van Groningen