Sequential composition of updates facilitated by the pipe operator.
Apply a function to the model (i.e. first component) of a ( model, Cmd msg ) pair.
Partially applied, we can also think of this as taking a function a -> b and lifting it into one of type ( a, Cmd msg ) -> ( b, Cmd msg ).
Create a ( model, Cmd msg) pair from the two arguments.
The implementation of this function is not very exciting — it is simply defined as addCmd cmd model = ( model, cmd ) — but it can still be quite useful in idiomatic code.
For example, one could write
{ model | power = 100 }
|> addCmd someCmd
|> andThen (setStatus Done)… instead of
( { model | power = 100 }, someCmd )
|> andThen (setStatus Done)See also andAddCmd.
Transform the message produced by the command inside a ( model, Cmd msg ) pair.
Remove one level of structure that results from composing functions of the form a -> ( b, Cmd msg ):
f : a -> ( b, Cmd msg )
g : b -> ( c, Cmd mgs )
map g << f : a -> ( ( c, Cmd msg ), Cmd msg )It is useful to know that andThen is defined as \f -> join << map f.
Compare the models of two ( model, Cmd msg) values.
Note that the presence of effects means that
> (save 9) == (map2 (^) (save 3) (save 2))
False : BoolThis function can be used for comparison when only the model is of interest:
> equals (save 9) (map2 (^) (save 3) (save 2))
True : BoolThese functions enable composition of updates by chaining together functions of the type a -> ( b, Cmd msg ).
When used in conjunction with the pipe operator, this combinator extracts the model from a ( model, Cmd msg ) value and passes it as input to the next function in a pipeline.
For example;
model
|> setPower 100
|> andThen (setDone True)Monadic functions of type a -> ( b, Cmd msg ) are the building blocks of a pipeline.
For instance, the type of setPower in the above example is Int -> Model -> ( Model, Cmd Msg ).
Take a list of a -> ( a, Cmd msg ) functions and run them sequentially, in a left-to-right manner, with the second argument as input.
Run an update if the given condition is True, otherwise do nothing.
For example;
model
|> when (power > 100) (setWarning Overflow)See also andThenIf.
Right-to-left composition of two functions that return ( model, Cmd msg ) values, passing the first component of the first return value as input to the second function.
This is analogous to ordinary function composition in the following way:
(<<) : (b -> c) -> (a -> b) -> a -> c
kleisli : (b -> ( c, Cmd msg )) -> (a -> ( b, Cmd msg )) -> a -> ( c, Cmd msg )These functions address the need to map functions with more than one parameter over ( model, Cmd msg ) inputs.
Combine two ( model, Cmd msg ) values by applying a function of two arguments
to their respective models.
Combine three ( model, Cmd msg ) values by applying a function of three arguments
to their respective models.
Combine four ( model, Cmd msg ) values by applying a function of four arguments
to their respective models.
Combine five ( model, Cmd msg ) values by applying a function of five arguments
to their respective models.
Combine six ( model, Cmd msg ) values by applying a function of six arguments
to their respective models.
Combine seven ( model, Cmd msg ) values by applying a function of seven arguments
to their respective models.
Trying to map a function (+) : number -> number -> number over two ( model, Cmd msg) inputs; first applying it to the first value
map (+) (save 4)… we end up with a result of type ( (number -> number), Cmd msg ).
To apply the function inside this value to another ( number, Cmd msg ) value, we use this function in the following way:
map (+) (save 4) |> andMap (save 5)In elm repl, we can verify that the result is what we expect:
> Tuple.first <| (map (+) (save 4) |> andMap (save 5))
9 : numberThis pattern scales in a nice way to functions of any number of arguments.
See also map2, map3, etc. If not sooner, you’ll need this function when you want to mapN for N > 7.
Thanks to currying, in Elm we can often omit function arguments:
f1 x = g x <==> f1 = g
f2 x = g (h x) <==> f2 = g << hMaking the arguments implicit in this way allows the programmer to think about the program more abstractly, and can (sometimes) lead to more readable program code.
update : Msg -> Model -> ( Model, Cmd Msg )
update msg =
case msg of
ButtonClicked ->
setMessage "The button was clicked!"
>> andThen haveCoffeeupdate msg model =
case msg of
ButtonClicked ->
model
|> setMessage "The button was clicked!"
|> andThen haveCoffeeThis combinator is useful for writing code in pointfree style.
Consider the following example:
gotoPage : Int -> Model -> ( Model, Cmd msg )
gotoPage = ...
nextPage model =
gotoPage (model.currentPage + 1) modelUsing this helper, the above code can be refactored as
nextPage =
using (\{ currentPage } -> gotoPage (currentPage + 1))This combinator is useful for writing code in pointfree style.
For example, the following code;
model
|> updateSomething
|> andThen (\newModel -> setCounterValue (newModel.counter + 1) newModel)… can be refactored as
model
|> updateSomething
|> andThen (with .counter (setCounterValue << (+) 1))Shortcut for andThen <<using.
Shortcut for \view -> andThen <<withview.
Turn a
modelvalue into a( model, Cmd msg )pair without adding any commands.