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
275 lines
5.7 KiB
Markdown
275 lines
5.7 KiB
Markdown
# 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:
|
|
```bash
|
|
elm repl
|
|
```
|
|
|
|
Try these expressions:
|
|
|
|
```elm
|
|
> 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:
|
|
|
|
```bash
|
|
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
|
|
|
|
```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`:
|
|
|
|
```elm
|
|
module Main exposing (main)
|
|
|
|
import Html exposing (text)
|
|
|
|
|
|
main =
|
|
text "Hello, Elm!"
|
|
```
|
|
|
|
Let's break this down:
|
|
|
|
### 1. Module Declaration
|
|
```elm
|
|
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
|
|
```elm
|
|
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
|
|
```elm
|
|
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)
|
|
|
|
```bash
|
|
elm reactor
|
|
```
|
|
|
|
Open http://localhost:8000 and click on `src/Main.elm`.
|
|
|
|
### Option 2: Compile to HTML
|
|
|
|
```bash
|
|
elm make src/Main.elm
|
|
```
|
|
|
|
This creates an `index.html` file you can open in a browser.
|
|
|
|
### Option 3: Elm Live (Hot Reloading)
|
|
|
|
```bash
|
|
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?
|
|
|
|
<details>
|
|
<summary>Solutions</summary>
|
|
|
|
```elm
|
|
> 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...
|
|
```
|
|
|
|
</details>
|
|
|
|
## Exercise 1.2: Modify Hello World
|
|
|
|
1. Change the greeting to include your name
|
|
2. Try using `String.toUpper` to make it ALL CAPS
|
|
|
|
<details>
|
|
<summary>Solution</summary>
|
|
|
|
```elm
|
|
module Main exposing (main)
|
|
|
|
import Html exposing (text)
|
|
|
|
|
|
main =
|
|
text (String.toUpper "Hello, Your Name!")
|
|
```
|
|
|
|
</details>
|
|
|
|
## Exercise 1.3: Multiple Elements
|
|
|
|
We need to use `Html.div` to group multiple elements:
|
|
|
|
```elm
|
|
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
|
|
|
|
<details>
|
|
<summary>Solution</summary>
|
|
|
|
```elm
|
|
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." ]
|
|
]
|
|
```
|
|
|
|
</details>
|
|
|
|
## 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](02-basics.md), 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 →](02-basics.md)
|