My first hours of Elm

I’ve been stalking the Elm project for a long while now, but only now sat down to get my hands dirty. Here I’ve tried to document my experiences as a newcomer, in case it’s useful to anyone.

Maybe eight months ago I jumped in headfirst and decided I’d compile elm from source so that I could contribute back right away. Unless you’re already steeped in the vagaries of cabal-install, I have to strongly recommend against this. Enough said :slight_smile:

There’s a large number of breadcrumbs to the tutorial (http:/guide.elm-lang.org) so as I wandered off into stackoverflow or blogs I was lead back time and time again. That part is working great!

I read the tutorial linearly up till the “Code Editor” portion. I’m a VIM person, and I’m on a chromebook, so sublime is a nonstarter for me, or else I’d have used it and been on my merry way, I’m sure. Instead I made several hours-long detours into figuring out the vim plugin system afresh (moved from pathogen to vim8 native packaging) and encountering a bug, it looks like it’s actually lacking a maintainer currently. I’m using the fork that’s currently maintained by Zaptic because I found on several issues that fork was working better than mainline.

I really dislike the pattern of npm install -g and instead I use linuxbrew and brew install yarn and this little bash script that I source before getting to work with elm. I’m quite happy with this, and it means that my elm dabblings are completely sandboxed away from my system packages.

$ cat .activate.sh
#!/not/executable/bash
HERE="$(dirname "$(readlink -f "${BASH_SOURCE:-$0}")")"

eval "$(brew shellenv)"
yarn install
PATH="$HERE/node_modules/.bin:$PATH"

After a couple weeks of false starts related to vim configuration and yarn fuddling, I sat down with a goal: I want to make a pong-like bouncing ball. SVG seems like an obvious fit here, since I’ve only got one object and I don’t feel like doing pixel math or learning openGL today.

To animate the thing, it seems like waking up to update the position of the ball every frame is overkill, but the only thing better I could find was the [Web Animations API][1] and it seems like too much for me to take on currently. So I settled on using the mdgriffith/elm-style-animation package, which seems like it’s been performant-enough for a large number of people.

The final subproblem is collision detection. While simple x - left < width math would have sufficed here, I went looking for a better solution. The [Intersection Observer API][2] does what I want and seems simple enough for me to deal with.

With some tech-stack decisions in hand I came back to elm. Here I made the mistake of skipping from the “Code Editor” section to the “Ports” section. I ran into several problems and bugs that would have been solved by reading “Javascript Interop” first. They were pretty surprising and annoying though, so I’ll note them here anyhow.

  1. elm reactor (which is used in the tutorial up till “Javascript Interop”) just completely [doesn’t work with ports][3]. Because the elm-reactor repo is archived, I can’t even leave a breadcrumb on that issue for the next person to bump into this. If elm reactor were enhanced to very simply detect a ports package and stop with an error, saying something along the lines of “hey you skipped the Javascript Interop page!”, that would have been the kind of pleasant error message Elm gives in other circumstances.
  2. Browser.sandbox (again, used in the guide before Javascript Interop) also conflicts 100% with ports. The user-facing symptom is that app.ports is undefined, which made me think I was misunderstanding ports entirely and defining them wrong. If the resulting javascript object had some sort of smart object put in place at the .ports attribute, that would be a helpful breadcrumb. If the type system could infer that the user wants ports but will never get them (due to sandbox), that would be even better. There’s a similar-ish behavior already in place when a user defines a port module without any ports.

To be continued…

I’ll try to read the rest of the guide in-order this time! :slight_smile:

[sic] Intentionally malformed due to “Sorry, new users can only put 2 links in a post.”
[1]: https:/developer.mozilla.org/en-US/docs/Web/API/Web_Animations_API
[2]: https:/developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API
[3]: https:/github.com/elm-lang/elm-reactor/issues/36

8 Likes

I noticed that while elm make gives an excellent error when I tried to leave a trailing comma on a struct (a habit from Python), elm-format does not. Note that the elm-format error is the one I immediately get when saving the file and using elm-vim, and so was the only error I saw until just now. This was really confusing until I took a wild guess that elm uses a trailing-commas-are-evil policy.

elm-format:

-- SYNTAX PROBLEM ------------------------------------------------- src/Main.elm

I ran into something unexpected when parsing your code!

19|         { init = init
              ^
I am looking for one of the following things:

    a closing bracket '}'
    whitespace

elm make:

-- EXTRA COMMA ---------------------------------------------------- src/Main.elm

I am partway through parsing a record, but I got stuck here:

19|         { init = init
20|         , update = PortsDemo.update
21|         , view = view,
22|         }
            ^
Trailing commas are not allowed in records. Try deleting the comma that appears
before this closing curly brace.

Note: If you are trying to define a record across multiple lines, I recommend
using this format:

    { name = "Alice"
    , age = 42
    , height = 1.75
    }

Notice that each line starts with some indentation. Usually two or four spaces.
This is the stylistic convention in the Elm ecosystem.

The elm compiler hints page for imports explains the
exposing (..) syntax but not exposing (X(..)). I couldn’t guess what that second syntax did at all.

I eventually found the reference I was looking for in the Haskell Report:

When the (..) form of import is used for a type or class, the (..) refers to all of the constructors, methods, or field names exported from the module.

Because the elm-reactor repo is archived, I can’t even leave a breadcrumb on that issue for the next person to bump into this

Ah, you’re running into one of a few common issues that relate to the move from 0.18 → 0.19. One of the changes in that release was that all of the separate official programs were consolodated into the elm binary. That’s why it’s elm reactor now where it was elm-reactor. Reactor is found in the compiler repo here; it looks like the last update was 6 months ago so it’s not quite dead yet!

(On that issue, try to also avoid googling for the core elm libraries, it still indexes the 0.18 packages and is a regular source of confusing for newcomers; use the package site directly or this awesome tool.)

elm-format also doesn’t report errors, it’s purely a code formatting tool! Most editor plugins are running elm make under the hood, that first error message is a compiler message too.

It’s worth pointing out that all the elm- tools aren’t official (eg elm-format elm-analyse elm-json); the elm install itself doesn’t require anything installed from npm (and you only need node if you plan on using the repl.)

Maybe eight months ago I jumped in headfirst and decided I’d compile elm from source so that I could contribute back right away

Posts like these are way more valuable to Evan and the core team rather than code contributions, thank you for posting this.

2 Likes

If you’d add that prose under the “Merged into elm/compiler” heading at GitHub - elm-lang/elm-reactor: Interactive development tool that makes it easy to develop and debug Elm programs., then this will be much more naturally discoverable. I saw the heading but it the meaning didn’t sink in till I got your explanation here.

Most projects that do this kind of thing will port their bugs to the new repo and leave breadcrumbs behind on the old, locked issues. I suspect this issue would be resolved by now if that had been done here – that locked, dead-end issue stifles community feedback and contribution.

I’ve dumped elm-vim for dense-analysis/ale since the language server integrations work far better than elm-vim could ever hope for anyway. It was mostly a syntax highlighter with a couple of extra commands tacked on.

antew/vim-elm-language-server may be a better place to look first though for an overview, since that’s where the Elm specific integration for Ale came from.

Thanks! I’ve seen ALE recommended by more than a couple people, but the setup looked daunting, and I was already spending too much time on it. Would you say that ALE is the modern replacement to the venerable Syntastic plugin?

I’ll have a go at it now though.

I’m also on a Chromebook and have found Sublime to be pretty great for all the web dev I do. I tried VSCode and the performance is atrocious on there. I want to get into Vim, or similar, but haven’t gotten there yet.

Here is my vim config, I’ve recently switched to using the language server protocol (lsp). Coc.nvim is quite nice for neovim or vim 8. The configuration for the elm language server is in the elm-tooling repo. Works pretty well for me!

Also more generally, I’d highly suggest looking for a local meetup or similar group where you can meet and discuss with other people using elm. Usually there are people happy to help elm beginners in their journey.

Don’t have a lot to add about the rest of the post (other than appreciation for a thoughtful writeup!), but I share your dislike of npm install --global and can happily recommend a tool to which I’ve had the pleasure of being a minor contributor: Volta. It solves the problem of needing “global” installs in a principled way, and a smart way, too, in that if you have a user default installation of tools like yarn or elm and a local installation (i.e. via package.json) it’ll use the local installation regardless of what the global is. And it’s written in Rust, so it’s very fast. I just set up a local Elm project this way myself and it’s quite nice!

3 Likes

If you want to run unit tests, then npm is required to install elm-test, which I believe is an official tool.

1 Like

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