[Fwd: updateLookupWithKey confusion]

Hello Folks,
Jean-Philippe suggests I put this question to
the libraries list. Any thoughts?
-------- Original Message --------
Subject: updateLookupWithKey confusion
Date: Mon, 26 Mar 2007 08:18:47 +0100
From: Adrian Hey

Adrian Hey wrote:
Hello Folks,
Jean-Philippe suggests I put this question to the libraries list. Any thoughts?
Well thinking about this a bit more I propose that both updateLookupWithKey and insertLookupWithKey (and possibly several other functions) should be deprecated and replaced with a more general mechanism that allows users to "roll their own" as far as these complex hybrid operations are concerned, such as that AVL tree already provide in the form of the BAVL type: http://darcs.haskell.org/packages/collections/Data/Tree/AVL/Zipper.hs If you consider the problem of visiting a particular tree node there are 3 different things you might do if the search succeeds: 1- Modify the associated value 2- Delete the association 3- Leave the associated value unchanged, in which case it would be nice to leave the entire map/tree whatever unchanged (not duplicate all the nodes on the search path). If the search fails you might.. 1- Insert a new association 2- Insert nothing. Add to that the various possibilities for what value should be returned (Old value? New value? Both?) and with/without key options and lazy/strict options and the whole thing becomes a bit of a nightmare. Now it's true that the BAVL option or similar requires the tree to be traversed twice if it's modified (only once if it isn't), but the second traversal does not require any comparisons and the relevant nodes will probably still be in cache from the first traversal. So it should be very cheap (compared to the cost of constructing the new heap records). Regards -- Adrian Hey
-------- Original Message -------- Subject: updateLookupWithKey confusion Date: Mon, 26 Mar 2007 08:18:47 +0100 From: Adrian Hey
To: Jean-Philippe Bernardy Hello Jean-Philippe,
There seems to be some confusion over this between Haddock documentation and the two implementations in Data.Map and Data.Map.AVL.
Is the 'looked up' value supposed to be the value bound to the corresponding key in the map before or after the update? The behaviour isn't specified in the Haddock of either version.
In Data.Map implementation you could get the value present before or after the update (depending on whether or not the association is deleted). Surely that's wrong?
In Data.Map.AVL you consistently get the value present before the update occurs, but I would have thought it be more useful to get the value after the update occurs (if any).
Anyway, I think the behaviour needs specifiying and whichever implementation(s) is not consistent with that spec needs modifying. I'm working on Data.Map.AVL at the moment so I'll fix it if it's wrong (and make it more efficient too).
Also, why don't we have a plain updateLookup? (without key), like we do for other funcions.
Regards -- Adrian Hey
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

On 3/31/07, Adrian Hey
Adrian Hey wrote:
Hello Folks,
Jean-Philippe suggests I put this question to the libraries list. Any thoughts?
Well thinking about this a bit more I propose that both updateLookupWithKey and insertLookupWithKey (and possibly several other functions) should be deprecated and replaced with a more general mechanism that allows users to "roll their own" as far as these complex hybrid operations are concerned
All of the functions that modify a single value in a single map can be implemented with alterA :: Applicative f => (Maybe v -> f (Maybe v)) -> k -> Map k v -> f (Map k v) In particular, -- I assume you want the old value out of updateLookup. updateLookupWithKey doUpdate key = Arrow.first getLast . alterA doChange key where doChange Nothing = (Last Nothing, Nothing) doChange (Just oldValue) = (Last (Just oldValue), doUpdate key oldValue) and insertLookupWithKey combine key value = Arrow.first getLast . alterA doChange key where doChange Nothing = (Last Nothing, Just value) doChange (Just oldValue) = (Last (Just oldValue), Just (combine key value oldValue)) I have a start on this at http://jeffrey.yasskin.info/darcs/hscollection/Data/FiniteMap.hs (written before I discovered http://darcs.haskell.org/packages/collections/, so now I'll have to merge them and send a patch). I haven't implemented alterA on Data.Map yet; it looks awkward but straightforward. If you don't intend to modify the map, lookup is probably enough, although with a slightly more general type for alterA involving "data Modification v = Delete | LeaveAlone | Replace v", we could subsume that too... -- Namasté, Jeffrey Yasskin

Jeffrey Yasskin wrote:
If you don't intend to modify the map, lookup is probably enough, although with a slightly more general type for alterA involving "data Modification v = Delete | LeaveAlone | Replace v", we could subsume that too...
Well this is the potential difficulty. In general (assuming the search succeeds) it will not be known whether or not to delete, replace or leave alone until after the current associated value has been obtained. So you need something like this. You could get away without the LeaveAlone constructor I guess (I.E. just use Maybe), but this won't allow the "leave the entire tree alone" option (this is basically what the current alter function does). What I have in mind is something very simple.. -- An "Open" map (abstract data type) data OMap k a -- O(log n). Open a Map at a the supplied current key openMap :: Ord k => k -> Map k a -> OMap k a -- O(1). Read the value associated with the current key. -- Returns Nothing if the search failed when the OMap was created readOMap :: OMap k a -> Maybe a -- O(log n). Delete the association at the current key -- (O(1) if the search failed when the OMap was created) deleteOMap :: OMap k a -> Map k a -- O(log n). Set a new associated value for the current key. writeOMap :: a -> OMap k a -> Map k a -- O(1). Close OMap, leaving the Map unmodified (not strictly necessary) closeOMap :: OMap k a -> Map k a -- O(1). Get the current key (not strictly necessary) readOMapKey :: OMap k a -> k That should be all users need to implement whatever hybrid operations they want. As to whether and how new values are calculated (and if so how strictly etc..) is entirely up to them. Regards -- Adrian Hey
participants (2)
-
Adrian Hey
-
Jeffrey Yasskin