[Haskell-cafe] Map unionWith generalization
Hans Aberg
haberg at math.su.se
Wed Jan 27 10:54:34 EST 2010
On 27 Jan 2010, at 16:33, Jan-Willem Maessen wrote:
>> I'm not sure why you want to throw in functions between maps in the
>> two first arguments. Then there is no requirement that single keys
>> are preserved.
>>
>> But it is a good idea to have a Maybe so that one can remove keys
>> on the fly.
>
> A good point. Technically, one should delimit the scope of the
> first two arguments:
>
> data KeyPreservingMapOperation k a b = AlwaysEmpty | Identity |
> MapMaybeWithKey (k -> a -> Maybe b)
>
> perform :: KeyPreservingMapOperation a b -> Map k a -> Map k b
> perform AlwaysEmpty = const empty
> perform Identity = id
> perform (MapMaybeWithKey f) = mapMaybeWithKey f
I'm thinking about
(k -> Maybe a -> Maybe b -> Maybe c) -> Map k a -> Map k b -> Map k c
The first two Maybe's tell if the keys are present, the last if one
wants it in the resulting map.
>>> When throwing together tree-like data structures, I often start by
>>> writing this function; it handles most of the bulk operations I
>>> might want to do as one-liners. It's got a messy, ugly type
>>> signature, but it does everything you want as efficiently as you
>>> want.*
>>
>> My guess is that is when you write things from scratch.
>
> Yes. On the other hand, I've repeatedly run into the same problem
> you're describing: a api that doesn't give me an efficient way to
> perform an operation I know to be very simple. If every map
> provided an operation like this one, then I can avoid writing my own
> library "from scratch" when I need it --- especially when "from
> scratch" means "fork the code and add what I need".
>
> So, library implementors: think hard about your "swiss army knife"
> combinators. You end up with messy functions with gigantic
> signatures. On the other hand, you can often add a couple of
> judicious INLINE annotations and remove tons of code from the rest
> of your library. Then expose them, and mark them as the functions
> of last resort that they truly are.
One can transverse the product of keys. Then I'm thinking about
(k1 -> k2 -> a -> b -> Maybe c -> Maybe(k, c)) -> Map k1 a -> Map
k2 b -> Map k c
The first Maybe tells if the key is already present; the second if one
wants it inserted.
The idea in both cases is to combine the modifying functions into one.
This simplifies the interface.
Hans
More information about the Haskell-Cafe
mailing list