Sequential composition of updates facilitated by the pipe operator.
save : a -> ( a, Platform.Cmd.Cmd msg )
Turn a model
value into a ( model, Cmd msg )
pair without adding any commands.
save model =
( model, Cmd.none )
map : (a -> b) -> ( a, Platform.Cmd.Cmd msg ) -> ( b, Platform.Cmd.Cmd msg )
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 )
.
addCmd : Platform.Cmd.Cmd msg -> a -> ( a, Platform.Cmd.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
.
mapCmd : (msg1 -> msg2) -> ( a, Platform.Cmd.Cmd msg1 ) -> ( a, Platform.Cmd.Cmd msg2 )
Transform the message produced by the command inside a ( model, Cmd msg )
pair.
join : ( ( a, Platform.Cmd.Cmd msg ), Platform.Cmd.Cmd msg ) -> ( a, Platform.Cmd.Cmd msg )
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
.
equals : ( a, Platform.Cmd.Cmd msg ) -> ( a, Platform.Cmd.Cmd msg ) -> Basics.Bool
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 : Bool
This function can be used for comparison when only the model is of interest:
> equals (save 9) (map2 (^) (save 3) (save 2))
True : Bool
These functions enable composition of updates by chaining together functions of the type a -> ( b, Cmd msg )
.
andThen : (b -> ( a, Platform.Cmd.Cmd msg )) -> ( b, Platform.Cmd.Cmd msg ) -> ( a, Platform.Cmd.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 )
.
sequence : List (a -> ( a, Platform.Cmd.Cmd msg )) -> a -> ( a, Platform.Cmd.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.
when : Basics.Bool -> (a -> ( a, Platform.Cmd.Cmd msg )) -> a -> ( a, Platform.Cmd.Cmd msg )
Run an update if the given condition is True
, otherwise do nothing.
For example;
model
|> when (power > 100) (setWarning Overflow)
See also andThenIf
.
kleisli : (b -> ( c, Platform.Cmd.Cmd msg )) -> (a -> ( b, Platform.Cmd.Cmd msg )) -> a -> ( c, Platform.Cmd.Cmd msg )
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.
map2 : (p -> q -> r) -> ( p, Platform.Cmd.Cmd msg ) -> ( q, Platform.Cmd.Cmd msg ) -> ( r, Platform.Cmd.Cmd msg )
Combine two ( model, Cmd msg )
values by applying a function of two arguments
to their respective models.
map3 : (p -> q -> r -> s) -> ( p, Platform.Cmd.Cmd msg ) -> ( q, Platform.Cmd.Cmd msg ) -> ( r, Platform.Cmd.Cmd msg ) -> ( s, Platform.Cmd.Cmd msg )
Combine three ( model, Cmd msg )
values by applying a function of three arguments
to their respective models.
map4 : (p -> q -> r -> s -> t) -> ( p, Platform.Cmd.Cmd msg ) -> ( q, Platform.Cmd.Cmd msg ) -> ( r, Platform.Cmd.Cmd msg ) -> ( s, Platform.Cmd.Cmd msg ) -> ( t, Platform.Cmd.Cmd msg )
Combine four ( model, Cmd msg )
values by applying a function of four arguments
to their respective models.
map5 : (p -> q -> r -> s -> t -> u) -> ( p, Platform.Cmd.Cmd msg ) -> ( q, Platform.Cmd.Cmd msg ) -> ( r, Platform.Cmd.Cmd msg ) -> ( s, Platform.Cmd.Cmd msg ) -> ( t, Platform.Cmd.Cmd msg ) -> ( u, Platform.Cmd.Cmd msg )
Combine five ( model, Cmd msg )
values by applying a function of five arguments
to their respective models.
map6 : (p -> q -> r -> s -> t -> u -> v) -> ( p, Platform.Cmd.Cmd msg ) -> ( q, Platform.Cmd.Cmd msg ) -> ( r, Platform.Cmd.Cmd msg ) -> ( s, Platform.Cmd.Cmd msg ) -> ( t, Platform.Cmd.Cmd msg ) -> ( u, Platform.Cmd.Cmd msg ) -> ( v, Platform.Cmd.Cmd msg )
Combine six ( model, Cmd msg )
values by applying a function of six arguments
to their respective models.
map7 : (p -> q -> r -> s -> t -> u -> v -> w) -> ( p, Platform.Cmd.Cmd msg ) -> ( q, Platform.Cmd.Cmd msg ) -> ( r, Platform.Cmd.Cmd msg ) -> ( s, Platform.Cmd.Cmd msg ) -> ( t, Platform.Cmd.Cmd msg ) -> ( u, Platform.Cmd.Cmd msg ) -> ( v, Platform.Cmd.Cmd msg ) -> ( w, Platform.Cmd.Cmd msg )
Combine seven ( model, Cmd msg )
values by applying a function of seven arguments
to their respective models.
andMap : ( a, Platform.Cmd.Cmd msg ) -> ( a -> b, Platform.Cmd.Cmd msg ) -> ( b, Platform.Cmd.Cmd msg )
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 : number
This 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 << h
Making 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 haveCoffee
update msg model =
case msg of
ButtonClicked ->
model
|> setMessage "The button was clicked!"
|> andThen haveCoffee
using : (a -> a -> b) -> a -> b
This 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) model
Using this helper, the above code can be refactored as
nextPage =
using (\{ currentPage } -> gotoPage (currentPage + 1))
with : (a -> b) -> (b -> a -> c) -> a -> c
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))
andAddCmd : Platform.Cmd.Cmd msg -> ( a, Platform.Cmd.Cmd msg ) -> ( a, Platform.Cmd.Cmd msg )
This function is a shortcut for andThen <<
addCmd
.
model
|> save
|> andAddCmd someCmd
andUsing : (b -> b -> ( a, Platform.Cmd.Cmd msg )) -> ( b, Platform.Cmd.Cmd msg ) -> ( a, Platform.Cmd.Cmd msg )
Shortcut for andThen <<
using
.
andWith : (b -> c) -> (c -> b -> ( a, Platform.Cmd.Cmd msg )) -> ( b, Platform.Cmd.Cmd msg ) -> ( a, Platform.Cmd.Cmd msg )
Shortcut for \view -> andThen <<
with
view
.
andThenIf : Basics.Bool -> (a -> ( a, Platform.Cmd.Cmd msg )) -> ( a, Platform.Cmd.Cmd msg ) -> ( a, Platform.Cmd.Cmd msg )
This function is a shortcut for \cond -> andThen <<
when
cond
.
model
|> save
|> andThenIf (power > 100) (setWarning Overflow)