elm / error-message-catalog

A catalog of broken Elm programs / data to improve error messages
BSD 3-Clause "New" or "Revised" License
174 stars 17 forks source link

Difficulty understanding Type Mismatch error for beginner #332

Open francois opened 4 years ago

francois commented 4 years ago

Over on Beginner thought process on type mismatch error, I described how I had difficulty understanding a Type Mismatch error:

-- TYPE MISMATCH ------------ /Users/francois/Projects/elm/scoutges/src/Main.elm

Something is off with the body of the `searchView` definition:

111|>    row []
112|>        [ search []
113|>            { text = queryString model
114|>            , placeholder = Just (placeholder [] (text "Type your query..."))
115|>            , label = labelHidden "Search"
116|>            , onChange = \q -> SearchFor q
117|>            }
118|>        ]

This `row` call produces:

    Element Msg

But the type annotation on `searchView` says it should be:

    Element msg

lydell explained the message thusly:

In the type annotation, you’ve said that this function can produce any type of message.

But in the function body, I see that this function only ever will produce messages of a type called Msg!

This means either:

  • That you have a misleading type annotation. It says any message, but only produces Msg messages. If so, change the type annotation to Msg instead of msg!
  • That you’ve accidentally used a specific message in this function, but you intended it to be generic. If so, replace SearchFor with something of a generic type!

The self-contained example is:

import Browser
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (onInput)

-- MAIN

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

-- MODEL

type alias Model =
    { name : String
    }

init : Model
init =
    Model ""

-- UPDATE

type Msg
    = Name String

update : Msg -> Model -> Model
update msg model =
    case msg of
        Name name ->
            { model | name = name }

-- VIEW

-- ****************
-- Change msg to Msg and the compilation error goes away
-- ****************
view : Model -> Html msg
view model =
    div []
        [ viewInput "text" "Name" model.name Name
        ]

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

I ran into this yesterday working with a co-worker who's new to Elm. Another couple aspects of this error that make it hard for beginners to troubleshoot are:

  1. What's the difference between Capital & lowercase "msg" ...
  2. How do I get Msg if I have msg aka: where to apply a toMsg : Msg -> msg function usually in some view code...
  3. Which direction do I go? EG: is it msg -> Msg or Msg -> msg and WHY.

In our case the idea was to rip some code from another part of the app, stitch it into a different context and make the minimal amount of changes to have something rendering on the screen (regardless of whether or not the behavior was correct)...

The more nefarious issue is what I call Top-Down vs Bottom-Up in Elm.... where

Issue in Bottom-Up is specifically WHICH types to change... eg: do we change the type of the implementation so it fits in it's context (which may or may not be possible depending on parent-child relationships between Msg's) or do we change the types of the context to satisfy the more general type of the child.

The whole premise of "Parent Child" relationships between Sum types in Elm seems to be the root of a significant deal of confusion, even amongst experienced Elm devs.

I know other "UI" focused language design communities offer a number of other organizational primitives like Streaming api's ala: rxjs / SolidJS ... OR Monadic DSL's vs Applicative DSL's ala: https://github.com/janestreet/bonsai/blob/761d04847d5f947318b64c0a46dffa17ad413536/docs/blogs/why_no_bind.md

And there's other ideas in the wild I've stumbled on but who's implementations don't have NEARLY the community backing that the Elm architecture has built up over the years.

QUESTION: I wonder if there's either One: an answer to the "which direction do I need to fix the types in?" or I suppose more philosophically relevant, is there a better "Parent Child" model we can leverage for helping Beginners understand how to model programs?