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 StringSo creating the type
Useralso created constructors namedAnonymousandNamed. If you want to create aUseryou 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