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
This commit is contained in:
274
lessons/01-introduction.md
Normal file
274
lessons/01-introduction.md
Normal file
@@ -0,0 +1,274 @@
|
||||
# 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)
|
||||
Reference in New Issue
Block a user