Elm Guide - Forms

I found this discussion of the Elm Guide Forms Tutorial:

I found the answer unsatisfying:

In your example the view function viewInput is simply saying:
“I need a function from you. I will use that function to create a Msg for your update. That function, that you give me, needs to expect a String.”

That the function that you pass in should expect a string, should make sense to you: Somehow you will want to “know”, what currently is written in the input you show to the user, right?

The function in question is:

viewInput : String -> String -> String -> (String -> msg) -> Html msg
viewInput t p v toMsg =
  input [ type_ t, placeholder p, value v, onInput toMsg ] []

Here is a call to it:

viewInput "text" "Name" model.name Name

“Name” is a variant of Msg:

type Msg
  = Name String
  | Password String
  | PasswordAgain String

So the answer given was that (String → msg) means that the func (viewInput) takes a function that takes a string and returns a message. But I’m confused because in the viewInput call, it is being passed a variant of Msg, not a String or a function. And even if (“Name”) is a String, it is not a function… is it?

The variants (also called value constructors) of Msg are functions! Because they construct values. Some functions don’t take any arguments.

-- ":" means type of
foo : Int -> Int -> Int -> Int
foo a b c = a + b + c

foo : Int -> Int -> Int -> Int -- no arguments applied to the function
foo 1 : Int -> Int -> Int -- one argument applied
foo 1 2 : Int -> Int -- two applied
foo 1 2 3 : Int -- all applied, the result is a value, or a function that takes no arguments
-- foo 1 2 3 4 -> compiler error

-- or

type Msg
    = Foo Int Int Int
    | Bar Int
    | Baz

Foo : Int -> Int -> Int -> Msg
Foo 1 : Int -> Int -> Msg
Foo 1 2 : Int -> Msg
-- aso
Bar : Int -> Msg
-- Baz takes no arguments
Baz : Msg
Baz 1 -- compiler error

Soo foo and Foo are both function that take 3 arguments, but foo returns an Int and Foo returns a Msg when all arguments being applied.

Every (useful) function, when supplied with enough arguments, ends up being fully applied, otherwise elm could not compile the program. I’m not so sure about that…

1 Like

I’m really just a beginner with Elm. Does this mean that when Bar 1 is called, by returning a Msg it triggers update? At that point, how is the 1 accessed in the update function (or in subsequent view functions?

You can use a case to extract the data from a custom type.

update :  Msg -> Model -> (Model, Cmd Msg) 
update msg model = 
    case msg of 
        Bar no -> 
             -- do something with no 

Alternatively you can pattern match directly on the value:

update :  Msg -> Model -> (Model, Cmd Msg) 
update msg model = 
    case msg of 
        Bar 1 -> 
             -- do something when is 1  
        Bar no -> 
             -- do something with other values 

Bar 1 is a way of declaring a value of type Msg. You put the tag Bar and a value of the type inside it, in this case Int type with value 1. Elm has a bunch of functions that are automatically created for you. Bar : Int -> Msg is one such function. So, I guess it is up to you if you view Bar 1 as syntax for declaring a value of type Msg OR just a function call. Both are valid in my perspective.

2 Likes

The difference between Html Msg and Html msg is that the second (with the small letter m) is more general. The Html msg includes all cases when the argument is actually of type Msg with the capital M, but it also includes many more variants.

If a function produces Html without any specific messages, then it can be declared in more general way to have return type of Html msg. But if you use anywhere inside the function body actual value of the specific type Msg with the capital M, then its return type must be also less general and more specific Html Msg with the capital M.

What it practically means is that if your helper function has more general declaration with small letter m, then it can be used in other modules with some other types of messages. Of course you would have to export it in the module declaration. If it uses specific type of messages Msg with the capital M, then it cannot be used with other types of messages. Even if you have in other module defined message type with the same name Msg, they are different because they originate in different modules.

Usually I start the function declaration with Html msg and only change it to Html Msg if the compiler insists on it.

1 Like

Thanks very much. I think im beginning to understand.

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.