You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This is a follow-up to #10798 which adds val update : ('a -> 'a) -> 'a Atomic.t -> unit. The motivation is to be able to implement pop in addition to push for the Treiber stack, more generally perform updates that also return a value.
The naming, type variable conventions and tuple order are inspired from fold_map-family functions:
val List.fold_left_map : ('acc -> 'a -> 'acc * 'b) -> 'acc -> 'a list -> 'acc * 'b list
(Edit: I initially had a claim that it is also "somehow consistent" with Seq.unfold : ('b -> ('a * 'b) option) -> 'b -> 'a t, but I don't find this convincing anymore. My best save would be to say that unfold is a dual operation, so it okay if the tuple is in the opposite order?)
Note that (unlike Haskell foldMap) the naming does not follow the pattern that foo_bar can be understood as the composition of foo and bar, with bar applied first to the input. On the other hand, update returns unit so fold ... (update ...) would not be interesting: there is no risk of conflict between two plausible interpretations of the name.
Finally, here are pointers to the comments from #10798 which discussed naming (that PR initially came with a modify_get function with exactly the type and behavior of fold_update, but it proved contentious and was dropped):
@NoahTheDuke had feedback on Clojure naming conventions for these functions ( Atomic.update (was: Atomic.modify, Atomic.modify_get) #10798 (comment) ) In particular he made the point that it would be nice to have a function that returns the value after the update, which fold_update can do but at the cost of some verbosity (a let-binding and a tuple).
Well, Option.fold does not have an input accumulator, or {Result,Either}.fold. You get an "iteration" feeling from List.fold because it is a recursive type, but this is not the case in general. (So one could argue that my use of 'acc is misleading, I'm happy to move to 'b if people prefer.)
I also liked Atomic.modify and Atomic.modify_get, but this ship has sailed, it is now Atomic.update :-)
map is for functions that return an instance of the container, so I would expect Atomic.map* to return a _ Atomic.t. On the other hand, fold is for functions that traverse the container to compute a value, which is what is going on here.
I find the name "fold" in "fold_update" fitting. Here is my justification for the annoying sort of category theorist such as myself: if one considers the "fold" operator for a type to be its recursion scheme, then "fold" for 'a Atomic.t would simply be ('a -> 'acc) -> 'a Atomic.t -> 'acc. In this case, "fold_update" can simply be viewed as a variant of this "fold," but with a "writer effect of type 'a" that automatically gets consumed. Basically, fold_update can be considered a foldM in the writer monad, followed (atomically) by a set operation that consumes the written result.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This is a follow-up to #10798 which adds
val update : ('a -> 'a) -> 'a Atomic.t -> unit. The motivation is to be able to implementpopin addition topushfor the Treiber stack, more generally perform updates that also return a value.The naming, type variable conventions and tuple order are inspired from
fold_map-family functions:(Edit: I initially had a claim that it is also "somehow consistent" with
Seq.unfold : ('b -> ('a * 'b) option) -> 'b -> 'a t, but I don't find this convincing anymore. My best save would be to say thatunfoldis a dual operation, so it okay if the tuple is in the opposite order?)Note that (unlike Haskell
foldMap) the naming does not follow the pattern thatfoo_barcan be understood as the composition offooandbar, withbarapplied first to the input. On the other hand,updatereturnsunitsofold ... (update ...)would not be interesting: there is no risk of conflict between two plausible interpretations of the name.Finally, here are pointers to the comments from #10798 which discussed naming (that PR initially came with a
modify_getfunction with exactly the type and behavior offold_update, but it proved contentious and was dropped):fold_updatecan do but at the cost of some verbosity (alet-binding and a tuple).map_updatefor this function ( Atomic.update (was: Atomic.modify, Atomic.modify_get) #10798 (comment) )