- Notifications
You must be signed in to change notification settings - Fork1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Define Map.update.#1026
Define Map.update.#1026
Conversation
stdlib/map.mli Outdated
@@ -86,6 +86,16 @@ module type S = | |||
of [x] in [m] disappears. | |||
@before 4.03 Physical equality was not ensured. *) | |||
val update: key -> ('a option -> 'a) -> 'a t -> 'a t |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Do you have a rationale for the signature off
? My instinct would rather say'a option -> 'a option
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
I can see two semantics for f returning None:
- do not add/update the binding (we are happy with the value already bound or the absence of binding)
- remove the binding
I am unsure of what is the most natural choice. What do you have in mind with your proposal?
My guess is that the current interface has a more obvious behaviour.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
- note that 1. is easy to perform by
id
onSome _
orNone
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
It would good to ensure that if we return the same option (physically, or perhaps checking physical equality under theSome
), the function returns the original map (physically) and doesn't allocate anything.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
This is, in fact, already done by@sbriais's implementation. But it could also be useful to specify it in the interface documentation.
(The current implementation uses'a option -> 'a
, which corresponds indeed to checking physical equality under theSome
-- this is strictly better than checking physical equality of the option, as the option will not be kept anyway.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
The documentation already says that (same phrasing as add documentation).
The current implementation is really copied-pasted from add, but f is called to compute data, instead of taking it as an argument.
stdlib/map.mli Outdated
@@ -86,6 +86,16 @@ module type S = | |||
of [x] in [m] disappears. | |||
@before 4.03 Physical equality was not ensured. *) | |||
val update: key -> ('a option -> 'a) -> 'a t -> 'a t | |||
(** [update x f m] returns a map containing the same bindings as | |||
[m], plus a binding of [x] to [f z] where [z] is either [None] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
this could be shortened to where [z] is [find_opt x m].
In Batteries we have
valmodify:key -> ('a ->'a) ->'at ->'at(** [modify k f m] replaces the previous binding for [k] with [f] applied to that value. If [k] is unbound in [m] or [Not_found] is raised during the search, [Not_found] is raised.*)valmodify_def:'a ->key -> ('a ->'a) ->'at ->'at(** [modify_def v0 k f m] replaces the previous binding for [k] with [f] applied to that value. If [k] is unbound in [m] or [Not_found] is raised during the search, [f v0] is inserted (as if the value found were [v0]).*)valmodify_opt:key -> ('aoption ->'aoption) ->'at ->'at(** [modify_opt k f m] allows to modify the binding for [k] in [m] or absence thereof.*) The Base library has two functions for value modification, the
Finally, Containers only has the
I think that if we are to add only one, the Should the name be Finally, I think that changes to the standard library should come with unit tests. If that can help, here are the
|
I would be in favor of adding this one and this oneonly. |
Regarding the tests, what is the policy? Add a new file, or extend the existing test for maps (ie basic/maps.ml) ? |
I don't know of a policy, that would be for the stdlib expert (@alainfrisch ) to decide. I'm fine with whichever, I think (The one part of the policy that I feel strongly about is that each new addition to the stdlib should come with tests. It is even easier for me to say as the implementor of a buggy new function in 4.04.0 thatshould have been better tested.) |
The stdlib expert is fine with whichever as well, but this is more a question for the testsuite expert. |
@Sbrais Tests definitely OK in the existing file. The only reason to branch off to a separate file would be if the test is particularly long (or, obviously, requires an extra harness of its own). |
a8305b0
toddba465
CompareDone. Should I fill also the "..." for the reviewers with all the names of the participants in this thread? |
Changes Outdated
@@ -83,6 +83,10 @@ Next version (4.05.0): | |||
### Standard library: | |||
- PR#7309, GPR#1026: Add update to maps. Allows to update a binding in | |||
a map or create a new binding if the key had no binding. (Sébastien |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Please respect the format and break the line before the open paren.
Only if you feel they have meaningfully contributed. For example, don't add me. |
* Refactoring: List.skip -> List.drop* Remove useless parameter* Remove useless local definition* Less code* Formatting---------Co-authored-by: Cuihtlauac ALVARADO <cuihtmlauac@tarides.com>
The following pattern seems frequent:
try Map.add key map (f (Map.find key map)) with Not_found -> Map.add key map default
It can be implemented more efficiently when having access to the concrete representation of maps to avoid to traverse twice the tree. This PR implements one possible solution to this problem and illustrates this by replacing two such patterns.
EDIT: Cfhttps://caml.inria.fr/mantis/view.php?id=7309 -- AF