Search code examples
elm

This `div` call produces: Html (String -> Msg) But the type annotation on `view` says it should be: Html Msg


I'm currently learning elm, I just stumbled on this problem where the div returns a Html (String -> Msg) instead of Html Msg.

error message I'm receiving

This div call produces:

Html (String -> Msg)

But the type annotation on view says it should be:

Html Msg
type alias Model =
   {
       firstNum: String,
       secondNum: String,
       answer: String
   }

init: Model 
init = { firstNum = "",
        secondNum = "",
        answer = ""}

type Msg =
    Add String| Minus String

update: Msg -> Model -> Model
update msg model =
    case msg of 
        Add  x -> { model | answer = x}
        Minus  y -> { model | answer = y}

view : Model -> Html Msg
view model =
    div [] 
    [
        input [ placeholder "Text to reverse", value model.firstNum] [],
        button [onClick Add] [text "add"],
        div [] [text model.answer]
    ]


main = 
  Browser.sandbox
  { init = init,
    update = update,
    view = view
  }


Solution

  • You define the Msg type as

    type Msg =
        Add String| Minus String
    

    with Add taking a String argument, but when you use it here:

    button [onClick Add] [text "add"],
    

    you're not giving it any argument at all.

    The underlying issue seems to be that your mental model of the Elm Architecture is wrong. You seem to consider messages as "operations" or function calls rather than events, where Add is a function that takes an argument to apply to the model.

    You should instead consider a message as a description of what triggered it. Instead of Add String, you might call it AddButtonClicked, with no arguments (in this case). Then have the update function do what it should based on what's in the model alone, which I'm guessing is an arithmetic operation on firstNum and secondNum.

    But you're also not populating those fields. To do so you need to use the onInput event, which does ask for a message that takes a String. You might add a new message FirstNumChanged String for example, then use it with input like this:

    input [ placeholder "Text to reverse", onInput FirstNumChanged, value model.firstNum] [],
    

    I'll leave it to you to figure out how to handle it in update.