ELI5: Commands Usage

I cannot seem to figure out what constitutes an acceptable Cmd in the context of update: Msg -> Model -> (Model, Cmd msg). For instance if I have defined a function myFunc : Html.msg I can’t seem to do

update msg model =
  MyMsg ->
     (model, myFunc)

As presented here, myfunc returns Html msg, but the return value from update should be a Cmd msg. They are different types and are not interchangable.

Html msg is often used for views. Is there some confusion here?

Also, Elm tries hard to produce useful compiler error messages. It’s always worth copying the error you get into your posts as it may help others help you understand what the compiler is telling you so you can work it out yourself in future.

Rgds, Jerry

Let’s start with type annotations:

update : Msg -> Model -> (Model, Cmd Msg)

So the command has to wrap a message of the same type that your update accepts.

(I see other people replying; hopefully taken together you can figure things out.)

:slight_smile:

I think I know the conceptual problem you are having. You wouldn’t really ever return an Html.msg from a command. You just update the model, and the views will automatically update.

Have you looked at the stuff like:

https://guide.elm-lang.org/

This may help, too:

https://guide.elm-lang.org/architecture/effects/

You need to return a Cmd Msg, not Html.msg from an update command with the signature:

update : Msg -> Model -> ( Model, Cmd Msg )

an example of that would be something like performing a Task:

http://package.elm-lang.org/packages/elm-lang/core/latest/Task#perform

or fetching http:

https://guide.elm-lang.org/architecture/effects/http.html

I have read through the guide but I guess it’s not clear to me what is a valid Cmd. For instance, in the guide Random.generate is considered a valid Cmd. Is this because its return type is Cmd msg? If so, how does one define a proper Cmd? Does it always have to return Cmd.none at some point?

Random.generate is considered a valid Cmd.

First, Cmd doesn’t mean anything on it’s own. It’s always a “command of something”. In the case randomness,

generate : (a -> msg) -> Generator a -> Cmd msg

So, second, Random.generate is not a command (of anything), but a function that returns a command. The msg type variable can be any type when talking about Random.generate in general. However, any time you actually call Random.generate, the msg gets filled in with a specific type. The random generator will generate a thing of a specific type, and the mapping function you provide (as the first argument) must accept that type. Whatever the mapping function outputs is the “of something” in “command of something”. The way it actually “does work” is hidden from you (but in this case, it gets the current time – an effect – and then uses that to seed a PRNG).

You define a proper command something like this:

type Msg = DiceRoll Int | ...

rollDie : Random.Generator Int
rollDie = Random.int 1 6

myCmd : Cmd Msg
myCmd = Random.generate DiceRoll rollDie

Regarding Cmd.none, that’s a misconception. Cmd.none doesn’t do anything, hence the type variable can be whatever it needs to be. There’s a pattern here:

  • x : List a implies x == []
  • y : Maybe b implies y == Nothing
  • z : Html msg implies z produces no messages (essentially, z has no bound event handlers)
  • c : Cmd msg implies c is Cmd.none, it produces no effects

(Note that you can use any lowercase string you want for a type variable, but msg and Msg are different - Msg is a specific type.) The pattern is that when you have a container whose elements are of any type, that container is actually empty.

Thank you, that’s very helpful. What about the case where your function does not utilize a function that already returns a Cmd Msg? So Random.generate is going to return a Cmd Msg but how do I create a function that returns a valid Cmd Msg de novo?

If you don’t need to do any “effects” – pseudorandomness, send an HTTP request, get the current time, send a value out a port – then use Cmd.none. The type Cmd msg will be unified with Cmd Msg.

1 Like

I see. Commands are only for things relying on effects outside the pure Elm environment then?

Yes, that’s correct. In a simple app, you use commands infrequently if at all. Rendering is done separately (render : Model -> Html Msg), and any events the HTML generates are passed back into update without any extra work on your part.

3 Likes