What is the 'msg' in 'HTML msg' in Elm actually?
tl;dr: as long as every function agrees on the type of msg
, and model
, they can be anything you want.
Just like the type parameter of List
, msg
can be anything. There is no restriction. To demonstrate, here's the classic increment/decrement example with the msg
being just an Int
:
-- These type aliases aren't needed, but makes it easier to distinguish
-- their roles in later type signatures
type alias Model = Int
type alias Msg = Int
update : Msg -> Model -> Model
update msg model =
model + msg
view : Model -> Html Msg
view model =
div []
[ button [ onClick 1 ] [ text "+1" ]
, div [] [ text <| String.fromInt model.count ]
, button [ onClick (-1) ] [ text "-1" ]
]
main : Program () Model Msg
main =
Browser.sandbox { init = 0, view = view, update = update }
So how does that work? The key is in the Browser.sandbox
function, as that's what connects everything together. Its type signature is:
sandbox :
{ init : model
, view : model -> Html msg
, update : msg -> model -> model
}
-> Program () model msg
where model
and msg
are type variables. Both of these can be replaced with any concrete type, as long as it matches up with the constraints given in this signature, which is that they must be the same across the init
, view
and update
functions. Otherwise we'll get a type error here. If, for example, update
requires a String
instead of an Int
, we'll get the error:
This argument is a record of type:
{ init : Model, update : String -> Model -> Model, view : Model -> Html Msg
}
But `sandbox` needs the 1st argument to be:
{ init : Model
, update : String -> Model -> Model
, view : Model -> Html String
}
It doesn't really know which is right or wrong, of course, just that there's a mismatch. But in an effort to be helpful it assumes String
is right and expects view
to return Html String
instead.
I hope that sufficiently answers your question. If not, comment and subscribe!
Short and Simple Explanation:
I have an xmas function like this:
wrapPresents : presents -> String
But what is the type, presents
? It can be anything that you want! You can substitute it with your own 'concrete type'. presents
is just a place holder!
wrapPresents : Boxes -> String
Now we have the "type" - we know that the first parameter must be a Box
type.
wrapPresents boxes = "All the boxes are now wrapped!"