I am very new and currently trying to learn Elm. I am coming from JS/React and haven't had any previous RFP experience.
I am in the Guide right here: http://guide.elm-lang.org/architecture/user_input/text_fields.html
The part I have problems with is update
and view
:
-- UPDATE
type Msg
= Change String
update : Msg -> Model -> Model
update msg model =
case msg of
Change newContent ->
{ model | content = newContent }
-- VIEW
view : Model -> Html Msg
view model =
div []
[ input [ placeholder "Text to reverse", onInput Change ] []
, div [] [ text (String.reverse model.content) ]
]
Let's start with the Msg declaration. The Guide says:
It takes one argument, in this case the Change function which was created when we declared the Msg type:
Change : String -> Msg
I don't see how this happened here:
type Msg
= Change String
How did we defined a Change function here? How did we define how that function works? To me it looks like we just declared the type of Msg, which somehow contains whatever Change
is and the type String
.
My second question is about the update:
update : Msg -> Model -> Model
update msg model =
case msg of
Change newContent ->
{ model | content = newContent }
To me this looks like update is a higher order function, which takes a Msg
and returns a function Model -> Model
. But then we define a function with two parameters. Does Msg -> Model -> Model
just means all but the last part are parameters?
Then we call the Change
function:
Change newContent ->
{ model | content = newContent }
What I don't get there is the arrow. Usually the arrow comes after a param definition. But here we have the result of a function before the ->
.
I hope my questions make sense, I am just very confused with this (presumably awesome) language.
When you declare type Msg = Change String
you're declaring a single type (Msg
) with one Constructor that accepts a String.
See the Elm guide section on Union Types (AKA Algebraic Data Types, ADTs).
Here's a sample:
type User = Anonymous | Named String
So creating the type
User
also created constructors namedAnonymous
andNamed
. If you want to create aUser
you must use one of these two constructors
Constructors are functions, so you call them like Change "a string"
(returns type Msg
)
Constructors also provide the ability to use pattern matching to extract the inner value in a union type. This is the use of ->
that you weren't familiar with.
case msg of
Change theString -> ... use theString ...
Your second question;
To me this looks like update is a higher order function, which takes a Msg and returns a function Model -> Model
Yes, that's more or less what's happening. The precedence rules for function application mean that you can call them without parenthesis. This is called currying, and it's also covered in the elm guide
Just to clarify a bit more the second part:
All functions are curried, meaning that update: Msg->Model->Model
can receive a Msg
and return a function Model->Model
or receive a Msg
and a Model
and return a Model
.
In reality, when you call update aMessage aModel
you are really calling update aMessage
which returns a function and then you pass aModel
to that function which will run the expressions in the body of the function and return the updated model.
The arrow is just part of the case.. of
syntax. Left side is the pattern you want to match, right side is the expression you wan to execute. In your case, your update will execute the expression only if the Msg was created using the Change constructor.
type Msg
= Change String | Delete
update : Msg -> Model -> Model
update msg model =
case msg of
Change newContent ->
{ model | content = newContent }
Delete ->
{ model | content = "" }
In the previous case, Msg can be constructed either with Change String
or with Delete
. The update function behaves differently according to the way the msg was constructed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With