Files
elm/lessons/01-introduction.md
Mark Gerrard 7d7986f3ab Initial commit: Elm tutorial for JavaScript developers
This tutorial includes:
- 7 progressive lessons covering Elm fundamentals
- Exercises with starter code
- Solutions for exercises
- Final project: Task Manager app with localStorage persistence

Topics covered:
- Basic syntax and types
- Functions and functional programming concepts
- The Elm Architecture (Model-View-Update)
- Lists and Maybe types
- HTTP requests and JSON decoding
- Ports for JavaScript interop
2026-03-11 11:07:15 +00:00

5.7 KiB

Lesson 1: Introduction & Your First Elm Program

Learning Goals

By the end of this lesson, you will:

  • Understand the Elm REPL
  • Create your first Elm project
  • Compile and run Elm code
  • Understand the project structure

The Elm REPL

Like Node.js, Elm has a REPL (Read-Eval-Print Loop) for experimenting with code.

Start it by running:

elm repl

Try these expressions:

> 1 + 1
2 : number

> "Hello" ++ " World"
"Hello World" : String

> String.length "Elm"
3 : Int

Notice something different from JavaScript? Elm tells you the type of each result!

Key Differences from JavaScript Console

JavaScript Elm REPL
"a" + "b" "a" ++ "b" (string concat uses ++)
1 + "1" = "11" Error! Can't mix types
console.log(x) Just type the expression

Type :exit to leave the REPL.

Your First Elm Project

Let's create a real project:

mkdir hello-elm
cd hello-elm
elm init

This creates:

hello-elm/
├── elm.json        # Project configuration (like package.json)
└── src/            # Your Elm source files go here

Understanding elm.json

{
    "type": "application",
    "source-directories": ["src"],
    "elm-version": "0.19.1",
    "dependencies": {
        "direct": {
            "elm/browser": "1.0.2",
            "elm/core": "1.0.5",
            "elm/html": "1.0.0"
        },
        "indirect": { ... }
    },
    "test-dependencies": { ... }
}

Comparison to JavaScript:

  • source-directories is like setting up your bundler's entry points
  • dependencies works like package.json but with direct/indirect separation
  • Unlike npm, Elm enforces semantic versioning automatically

Hello World

Create src/Main.elm:

module Main exposing (main)

import Html exposing (text)


main =
    text "Hello, Elm!"

Let's break this down:

1. Module Declaration

module Main exposing (main)
  • Every Elm file is a module
  • exposing (main) says "make main available to other modules"
  • JavaScript equivalent: export { main }

2. Imports

import Html exposing (text)
  • Import the Html module
  • exposing (text) lets us use text directly instead of Html.text
  • JavaScript equivalent: import { text } from 'html'

3. The main Function

main =
    text "Hello, Elm!"
  • main is the entry point (like ReactDOM.render or your app's root)
  • text creates an HTML text node
  • No return keyword needed - the last expression is the return value

Running Your Code

Option 1: Elm Reactor (Development Server)

elm reactor

Open http://localhost:8000 and click on src/Main.elm.

Option 2: Compile to HTML

elm make src/Main.elm

This creates an index.html file you can open in a browser.

Option 3: Elm Live (Hot Reloading)

elm-live src/Main.elm -- --open

This opens your browser and reloads on file changes (like webpack-dev-server).

Exercise 1.1: Experiment in the REPL

Start elm repl and try:

  1. Calculate 123 * 456
  2. Concatenate three strings: "I", " love", " Elm"
  3. Find the length of "functional programming"
  4. Try 1 + "hello" - what happens?
Solutions
> 123 * 456
56088 : number

> "I" ++ " love" ++ " Elm"
"I love Elm" : String

> String.length "functional programming"
22 : Int

> 1 + "hello"
-- TYPE MISMATCH --
The (+) operator is expecting both arguments to be numbers...

Exercise 1.2: Modify Hello World

  1. Change the greeting to include your name
  2. Try using String.toUpper to make it ALL CAPS
Solution
module Main exposing (main)

import Html exposing (text)


main =
    text (String.toUpper "Hello, Your Name!")

Exercise 1.3: Multiple Elements

We need to use Html.div to group multiple elements:

module Main exposing (main)

import Html exposing (div, h1, p, text)


main =
    div []
        [ h1 [] [ text "Welcome to Elm" ]
        , p [] [ text "This is a paragraph" ]
        ]

The pattern is: element attributes children

  • div [] - a div with no attributes
  • [ h1 ..., p ... ] - list of children

Create a page with:

  1. A heading with your name
  2. A paragraph about why you're learning Elm
  3. Another paragraph about your programming background
Solution
module Main exposing (main)

import Html exposing (div, h1, p, text)


main =
    div []
        [ h1 [] [ text "Hi, I'm Learning Elm!" ]
        , p [] [ text "I want to learn functional programming." ]
        , p [] [ text "I have experience with JavaScript." ]
        ]

Key Takeaways

  1. Elm is typed - The compiler tells you types and catches errors early
  2. No semicolons or braces - Whitespace and indentation matter
  3. Everything is an expression - No statements, everything returns a value
  4. String concatenation uses ++ - Not + like JavaScript
  5. HTML is just functions - div, h1, p are all functions

Common Mistakes from JavaScript Developers

Mistake Why It Happens Elm Way
Using + for strings JavaScript habit Use ++
Forgetting type annotations JS doesn't have them Optional but recommended
Using return JS function habit Last expression is returned
Using {} for blocks JS syntax Use indentation

What's Next?

In Lesson 2, we'll dive deeper into Elm's type system and learn about:

  • Primitive types (Int, Float, String, Bool)
  • Type annotations
  • Records (like JavaScript objects, but better!)
  • Custom types

Next: Lesson 2 - Basic Syntax & Types →