elm / compiler

Compiler for Elm, a functional language for reliable webapps.
https://elm-lang.org/
BSD 3-Clause "New" or "Revised" License
7.48k stars 659 forks source link

Newbies and the evil of import aliases #2230

Open ravensiris opened 2 years ago

ravensiris commented 2 years ago

The issue

After testing elm for a bit I've encountered this error:

    > elm make src/Main.elm
    Detected problems in 1 module.
    -- TYPE MISMATCH -------------------------------------------------- src/Main.elm

    The 2nd argument to `div` is not what I expect:

    12|     Html.toUnstyled <| div [] [ svg [] [] ]
                                      ^^^^^^^^^^^^^
    This argument is a list of type:

        List (Html.Html msg)

    But `div` needs the 2nd argument to be:

        List (Html.Html msg)

    Hint: I always figure out the argument types from left to right. If an argument
    is acceptable, I assume it is “correct” and move on. So the problem may actually
    be in one of the previous arguments!

Which is very much unreadable. How does List(Html.Html msg) not match List(Html.Html msg) ? Makes no sense just looking at the error alone.

Main.elm code:

    module Main exposing (..)

    import Html.Styled as Html exposing (a, div, text)
    import Html.Styled.Attributes as Attr exposing (css)
    import Svg exposing (path, svg)
    import Svg.Attributes as SvgAttr

    main =
        Html.toUnstyled <| div [] [ svg [] [] ]

The culprit

After fiddling around some more I found the culprit:

 import Html.Styled as Html exposing (a, div, text)

Using as Html to be exact.

Code cleansed of evil import aliases

After testing this:

module Main exposing (..)

import Html.Attributes as Attr
import Html.Styled exposing (a, div, text)
import Svg as Svg exposing (svg)
import Tailwind.Breakpoints as Bp
import Tailwind.Utilities as Tw

main = 

    div
        []
        [ svg [] [] ]

The issue was much more clear, causing this compile error:

The 2nd argument to `div` is not what I expect:

11|     div
12|         []
13|         [ svg [] [] ]
            ^^^^^^^^^^^^^
This argument is a list of type:

    List (Html.Html msg)

But `div` needs the 2nd argument to be:

    List (Html.Styled.Html msg)

Hint: I always figure out the argument types from left to right. If an argument
is acceptable, I assume it is “correct” and move on. So the problem may actually
be in one of the previous arguments!

See how it is now: List (Html.Html msg) and List (Html.Styled.Html msg) ?

My hopes

My suggestion is for the compile errors to expand import aliases(as) whenever left and right side have ambiguous types or do it always. Or oh well it was all my fault for using as improperly.

Some haskell exercises

Below I tried to replicate the issue in haskell. My haskell is pretty bad but hopefully I replicated it well.

Main.hs

import Html (Html, makeHtml)
import HtmlTwo as Html (fromHtml)

main = do
  putStrLn $ show $ (fromHtml . makeHtml) "test"

Html.hs

module Html (Html, makeHtml, fromHtml)
where

newtype Html a = Html a deriving Show

makeHtml :: a -> Html a
makeHtml a = Html a

fromHtml :: Html a -> a
fromHtml (Html a) = a

HtmlTwo.hs

module HtmlTwo (Html, makeHtml, fromHtml)
where
newtype Html a = Html a deriving Show

makeHtml :: a -> Html a
makeHtml a = Html a

fromHtml :: Html a -> a
fromHtml (Html a) = a

Compile error

> ghc -dynamic Main.hs
[3 of 3] Compiling Main             ( Main.hs, Main.o )

Main.hs:6:33: error:
    • Couldn't match type: Html String
                     with: HtmlTwo.Html a0
      Expected: String -> HtmlTwo.Html a0
        Actual: String -> Html String
      NB: ‘HtmlTwo.Html’ is defined in ‘HtmlTwo’
          ‘Html’ is defined in ‘Html’
    • In the second argument of ‘(.)’, namely ‘makeHtml’
      In the expression: fromHtml . makeHtml
      In the second argument of ‘($)’, namely
        ‘(fromHtml . makeHtml) "test"’
  |
6 |   putStrLn $ show $ (fromHtml . makeHtml) "test"
  |                                 ^^^^^^^^

Input

If I didn't butcher the haskell example it should show that haskell properly expands the types with module names ignoring aliases. Also NB: ‘HtmlTwo.Html’ is defined in ‘HtmlTwo’ ‘Html’ is defined in ‘Html’ seems to be really helpful. Hopefully it would be added to the elm compiler in the future, sparing newbies from having cryptic errors as such.

github-actions[bot] commented 2 years ago

Thanks for reporting this! To set expectations:

Finally, please be patient with the core team. They are trying their best with limited resources.