Search code examples
elm

Elm View Function Returns a Function Instead of the Value of it


The Elm Compiler gives me this error in my view function ...

TYPE MISMATCH - Something is off with the 2nd branch of this case expression:

       div [] [
        div [] [text (String.fromInt value)],
        div [] [button [ onClick identity ] [ text "Enter number" ]]]

This div call produces:

Html #(a -> a)#

But the type annotation on view says it should be:

Html #Msg#Elm

Does anyone know how I can fix this issue?

Thank you!

module Main exposing (..)

import Browser
import Html exposing (Html, button, div, text)
import Html.Events exposing (onClick)



-- MAIN


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



-- MODEL


type alias Model = 
    Result String Int


init : Model
init =
  Result.Ok 0



-- UPDATE


type alias Msg = Int



update : Msg -> Model -> Model
update msg model =
  collatz msg


collatz : Int -> Result String Int
collatz start =
    if start <= 0 then
        Result.Err "Only positive numbers are allowed"

    else
        Result.Ok (collatzHelper start 0)


collatzHelper : Int -> Int -> Int
collatzHelper start counter =
    if start == 1 then
        counter

    else if modBy 2 start == 0 then
        collatzHelper (start // 2) (counter + 1)

    else
        collatzHelper (3 * start + 1) (counter + 1)



-- VIEW


view : Model -> Html Msg
view model =
    case model of
        Err err ->
            div [] [text err]

        Ok value ->
            div [] [
            div [] [text (String.fromInt value)],
            div [] [button [ onClick identity ] [ text "Enter number" ]]]



Solution

  • The compiler error message, as always with Elm, is fairly straightforward to understand. The problem is the onClick attribute in this line:

    div [] [button [ onClick identity ] [ text "Enter number" ]]
    

    As the compiler says, this has type a -> a, when it's expected to have type Msg, which in your case is the same as Int. That is, you've passed a function and it should be an integer.

    Since value here is indeed an Int, that seems the natural choice to use here:

    div [] [button [ onClick value ] [ text "Enter number" ]]
    

    and this does indeed compile. However, this app doesn't seem particularly useful, because the user has no way to change the value displayed. You will need to include some sort of numeric input in your app to allow that - and then you will need a new alternative in your Msg type to handle the change of value.

    Judging by this and your previous question (which is where I assume you got the idea of using identity as an onClick value - unfortunately that doesn't work in general), you seem to be struggling a bit with how the Elm Architecture works, so if you haven't already I would strongly recommend going through the tutorial.