Esc
Start typing to search...

Code Examples

Explore Keel through practical code examples. Click any example to open it in the playground.

437 examples

Basics

Collections

Bracket List

collections
let xs : [Int] = [1, 2, 3]

let ys : [Int] = [4, 5, 6]

ys

Building Lists

collections
-- Prepend element
let list1 =
    1 :: [2, 3]
    -- Concatenate lists

let list2 = [1, 2] ++ [3, 4]
...

Dataframe Fromrecords

collections
import DataFrame

DataFrame.fromRecords
    [ { name = "Alice", score = 95 }
    , { name = "Bob", score = 87 }
    , { name = "Charlie", score = 92 }
...

Filter

collections
-- Filter: keep matching elements
import List

[1, 2, 3, 4] |> List.filter (|x| x > 2)

-- [3, 4]

Fold

collections
-- Fold: reduce to single value
import List

[1, 2, 3, 4] |> List.foldl (|acc x| acc + x) 0

-- 10

Length

collections
import List

fn length : [a] -> Int
fn length list =
    case list of
        [] -> 0
...

List Access

collections
let items = [10, 20, 30]

items[0]

List Ops

collections
-- Prepend (cons)
let consed =
    1 :: [2, 3]
    -- Concatenation

let joined = [1, 2] ++ [3, 4]
...

List Pattern

collections
let list = [1, 2, 3]

case list of
    [] -> "empty"
    [x] -> "single element"
    x :: xs -> "has multiple elements"

List Statistics

collections
-- List statistics: mean, median, variance, std, percentile, mode
import List
import Maybe

-- Integer list statistics
let scores = [60, 70, 80, 90, 100]
...

Lists

collections
let numbers = [1, 2, 3, 4, 5]

let names = ["Alice", "Bob", "Charlie"]

let empty : [Int] = []
...

Map

collections
-- Map: transform each element
import List exposing map

[1, 2, 3] |> map (|x| x * 2)  -- [2, 4, 6]

Multiline List

collections
let users =
    [ { name = "Alice", age = 30 }
    , { name = "Bob", age = 25 }
    , { name = "Charlie", age = 35 }
    ]
...

Multiline Record

collections
let config =
    { host = "localhost"
    , port = 8080
    , debug = True
    , maxConnections = 100
    }
...

Nested Record

collections
let data =
    { user = { profile = { name = "Alice" } }
    }

data.user.profile.name

Record Access

collections
let user = { name = "Alice", age = 30 }

user.name

Record Destructure

collections
let person = { name = "David", age = 40 }

let { name, age } = person

name

Record Multi Update

collections
let person = { name = "Alice", age = 30 }

let updated = { person | age = 31, name = "Alicia" }

updated.name

Record Pattern

collections
let person = { name = "Bob", age = 25 }

case person of
    { name, age } -> name

Record Rest

collections
let user =
    { name = "Carol"
    , age = 35
    , email = "carol@example.com"
    }
...

Record Update

collections
-- Record update syntax

let person = { name = "Alice", age = 30 }

let older = { person | age = 31 }
...

Record Workflow

collections
-- Record update creates a new record
let user = { name = "Eve", age = 28 }

let updatedUser = { user | age = user.age + 1 }

updatedUser.name

Records

collections
let user =
    { name = "Alice"
    , age = 30
    , email = "alice@example.com"
    }
...

Reverse

collections
import List

fn reverse : [a] -> [a]
fn reverse list =
    case list of
        [] -> []
...

Tuple Access

collections
let pair = (1, "hello")

let first = pair.0  -- 1

let second = pair.1  -- "hello"
...

Tuple Access 2

collections
let triple = (True, 42, "world")

triple.2

Tuple Destructure

collections
let (x, y) = (10, 20)

x + y

Tuple Pattern

collections
let pair = (3, 0)

case pair of
    (0, 0) -> "origin"
    (x, 0) -> "on x-axis"
    (0, y) -> "on y-axis"
...

Tuples

collections
let pair = (1, "one")

let triple = (True, 42, "hello")

let point = (3.5, 4.2)
...

Control Flow

Case Enum

control-flow
enum Color = Red | Green | Blue

let color = Color::Green

let description =
    case color of
...

Catchall

control-flow
enum Color = Red | Green | Blue

let color = Color::Green

case color of
    Color::Red -> "primary"
...

Else If

control-flow
let score = 85

let grade =
    if score >= 90 then
        "A"
    else if score >= 80 then
...

Exhaustive

control-flow
enum Color = Red | Green | Blue

let color = Color::Blue

case color of
    Color::Red -> "red"
...

Guard Exhaustive

control-flow
let x = 0

case x of
    n if n > 0 -> "positive"
    n if n < 0 -> "negative"
    _ -> "zero"

Guards

control-flow
let number = -5

case number of
    n if n < 0 -> "negative"
    n if n == 0 -> "zero"
    n if n > 0 -> "positive"
...

If Expression

control-flow
let x = 5

let result =
    if x > 0 then
        "positive"
    else
...

If Multiline

control-flow
let condition = True

if condition then
    "yes"
else
    "no"

If Same Type

control-flow
let condition = True

-- Valid: both branches return Int
if condition then
    1
else
...

If Type Mismatch

control-flow
if False then
    1
else
    "zero"  -- Error: type mismatch

List Pattern

control-flow
let numbers = [1, 2, 3]

case numbers of
    [] -> "empty list"
    [x] -> "single element"
    [x, y] -> "two elements"
...

Maybe Handling

control-flow
let maybeUser = Just "Alice"

let displayName =
    case maybeUser of
        Just name -> name
        Nothing -> "Anonymous"
...

Maybe Type

control-flow
-- norun
enum Maybe a = Just(a) | Nothing

Multiple Head

control-flow
let list = [1, 2, 3, 4]

case list of
    a :: b :: rest -> a + b
    x :: xs -> x
    [] -> 0

Nested Match

control-flow
let data = (3, 4)

case data of
    (a, b) -> a + b

Or Patterns

control-flow
enum Day
    = Monday
    | Tuesday
    | Wednesday
    | Thursday
    | Friday
...

Qualified Enum

control-flow
enum Color = Red | Green | Blue

let color = Color::Green

case color of
    Color::Red -> "fire"
...

Recursive Sum

control-flow
fn sum : [Int] -> Int
fn sum list =
    case list of
        [] -> 0
        x :: xs -> x + sum xs
...

Result Handling

control-flow
import String

let parseResult = Ok 42

case parseResult of
    Ok n -> "Parsed: " ++ String.fromInt n
...

Result Type

control-flow
-- norun
enum Result a e = Ok(a) | Err(e)

Data Contracts

Display Mapped

data-contractsenumsdataframe
import DataFrame

enum Country
    = Germany
    | BurkinaFaso "Burkina Faso"
    | UnitedKingdom "United Kingdom"
...

Geographic

data-contractsenumsdataframe
import DataFrame

enum Region
    = NorthEast "North East"
    | NorthWest "North West"
    | Midlands
...

Inline Value Labels

data-contractsenumsdataframe
import DataFrame

enum Education = Primary | Secondary | Tertiary | Postgraduate

let survey : DataFrame {
    respondent_id: Int,
...

Multiple Columns

data-contractsenumsdataframe
import DataFrame

enum City = Berlin | Munich | Hamburg
enum Gender = Male | Female | Other

let data : DataFrame { city: City, gender: Gender, .. } = DataFrame.readCsv "demographics.csv"

Non Exhaustive

data-contractsenumsdataframe
import DataFrame

enum YesNo = No | Yes

let data : DataFrame {
    response: [(0, YesNo::No), (1, YesNo::Yes), ..]
...

Open Closed Schema

data-contractsenumsdataframe
import DataFrame

enum Status = Active | Inactive | Pending

let exact : DataFrame { id: Int, name: String, status: Status } = DataFrame.readCsv "users.csv"
...

Stata Value Labels

data-contractsenumsdataframe
-- norun

import DataFrame

enum Employment
    = Employed        (ValueLabel 1 "Employed")
...

String Enum

data-contractsenumsdataframe
import DataFrame

enum City = Berlin | Munich | Hamburg

let data : DataFrame { name: String, city: City, .. } = DataFrame.readCsv "users.csv"

Survey Use Case

data-contractsenumsdataframe
import DataFrame

enum AgeGroup
    = Under18 "Under 18"
    | Young "18-34"
    | Middle "35-54"
...

Value Label Shorthand

data-contractsenumsdataframe
-- norun

import DataFrame

enum Education
    = Primary     (ValueLabel 1 "Primary")
...

Value Label Type

data-contractsenumsdataframe
import DataFrame
import ValueLabelSet

enum Education
    = Primary (ValueLabel 1 "Primary")
    | Secondary (ValueLabel 2 "Secondary")
...

Dataframe

Dataframe Corr

dataframestatisticscorrelation
import DataFrame

-- Pearson correlation matrix
let data =
    DataFrame.fromRecords
        [ { x = 1, y = 2 }
...

Dataframe Corr Spearman

dataframestatisticscorrelation
import DataFrame

-- Spearman rank correlation matrix (robust to outliers and non-linear monotone relationships)
let data =
    DataFrame.fromRecords
        [ { x = 1, y = 2 }
...

Dataframe Quantiles

dataframestatisticsquantile
import DataFrame

-- Multiple quantiles in one call
let data =
    DataFrame.fromRecords
        [ { score = 78 }
...

Dataframe Statistics

dataframestatisticsmean
import DataFrame

-- Column-wise descriptive statistics
let data =
    DataFrame.fromRecords
        [ { score = 78 }
...

Expr Aggregation

dataframeexpraggregation
-- Aggregation with DataFrame.Expr
import DataFrame

import DataFrame.Expr as Expr

DataFrame.fromRecords
...

Expr Arithmetic

dataframeexprarithmetic
-- Pipe-style arithmetic: Expr.mul for column * column
import DataFrame
import DataFrame.Expr exposing col
import Result

import DataFrame.Expr as Expr
...

Expr Basics

dataframeexprexpressions
-- DataFrame.Expr for composable column operations
import DataFrame
import DataFrame.Expr exposing col
import Result

import DataFrame.Expr as Expr
...

Expr Captured Var

dataframeexprvariable
-- Outer-scope variables are captured in expressions
import DataFrame
import Result

import DataFrame.Expr as Expr
...

Expr Case

dataframeexprconditional
-- Multi-branch conditional with Expr.cond
import DataFrame
import Result

import DataFrame.Expr as Expr
...

Expr Comparison

dataframeexprcomparison
-- Pipe-style comparison: Expr.gte for column >= literal
import DataFrame
import DataFrame.Expr exposing col
import Result

import DataFrame.Expr as Expr
...

Expr Concat

dataframeexprstring
import DataFrame
import Result

import DataFrame.Expr as Expr

let full = Expr.concatMany " " [@first, @last]
...

Expr Conditional

dataframeexprconditional
-- Conditional expressions with DataFrame.Expr
import DataFrame
import DataFrame.Expr exposing col, lit
import Result

import DataFrame.Expr as Expr
...

Expr Cumsum Extra

dataframewindowcumsum
import DataFrame

-- Running sum per region using window functions
DataFrame.fromRecords
    [ { region = "East", revenue = 100 }
    , { region = "East", revenue = 200 }
...

Expr Cumulative

dataframewindowcumsum
import DataFrame

-- Cumulative sum and mean per region using window functions
DataFrame.fromRecords
    [ { region = "East", revenue = 100 }
    , { region = "East", revenue = 200 }
...

Expr Date

dataframeexprstring
import DataFrame
import DataFrame.Expr exposing col, lit
import Result

import DataFrame.Expr as Expr
...

Expr Datetime

dataframeexprstring
import DataFrame
import DataFrame.Expr exposing col
import Result

import DataFrame.Expr as Expr
...

Expr Float Pred

dataframeexprnull
import DataFrame
import DataFrame.Expr exposing col
import Result

import DataFrame.Expr as Expr
...

Expr If Else

dataframeexprconditional
-- Simple if/else conditional with Expr.cond
import DataFrame
import Result

import DataFrame.Expr as Expr
...

Expr Import

dataframeexprimport
import DataFrame
import Result

import DataFrame.Expr as Expr

let source =
...

Expr In

dataframeexprcomparison
-- Membership test: Expr.in filters rows where the column value is in a list
import DataFrame
import Result

import DataFrame.Expr as Expr
...

Expr Infix Arithmetic

dataframeexprinfix
-- Infix arithmetic operators work directly on column references
import DataFrame
import Result

import DataFrame.Expr as Expr
...

Expr Infix Boolean

dataframeexprinfix
-- Boolean logic: && and || work with Expr values
import DataFrame
import Result

let df =
    DataFrame.fromRecords
...

Expr Infix Chained

dataframeexprinfix
-- Chained infix operations respect operator precedence
import DataFrame
import Result

import DataFrame.Expr as Expr
...

Expr Infix Comparison

dataframeexprinfix
-- Infix comparison operators produce boolean Expr for filtering
import DataFrame
import Result

let df =
    DataFrame.fromRecords
...

Expr Infix Scalar

dataframeexprinfix
-- Scalars are auto-coerced to Expr when used with infix operators
import DataFrame
import Result

import DataFrame.Expr as Expr
...

Expr Math

dataframeexprmath
-- Math functions: abs
import DataFrame
import Result

import DataFrame.Expr as Expr
...

Expr Mutate

dataframeexprapplyExprs
-- Add a computed column with applyExprs using tuple syntax
import DataFrame
import Result

import DataFrame.Expr as Expr
...

Expr Null

dataframeexprnull
-- Null handling: fillNull
import DataFrame
import DataFrame.Expr exposing col
import Result

import DataFrame.Expr as Expr
...

Expr Operators Overview

dataframeexproperators
-- Operators work directly on column references
import DataFrame
import Result

import DataFrame.Expr as Expr
...

Expr Quantile

dataframeexprquantile
import DataFrame

import DataFrame.Expr as Expr

-- Interquartile range components
let q1 =
...

Expr Regex String

dataframeexprstring
-- Extract year from date strings using regex capture
import DataFrame
import Result

import DataFrame.Expr as Expr
...

Expr Reuse

dataframeexprreuse
import DataFrame
import Result

import DataFrame.Expr as Expr

let revenue = @price * @qty
...

Expr Rolling

dataframewindowrolling
import DataFrame

-- Rolling window operations using partitionBy + withRollingSum/withRollingMean
DataFrame.fromRecords
    [ { region = "East", value = 1 }
    , { region = "East", value = 2 }
...

Expr Rolling Extra

dataframewindowrolling
import DataFrame

-- 7-day rolling average using window functions
DataFrame.fromRecords
    [ { dept = "East", sales = 10 }
    , { dept = "East", sales = 20 }
...

Expr Split

dataframeexprstring
import DataFrame
import DataFrame.Expr exposing col
import Result

import DataFrame.Expr as Expr
...

Expr String Extra

dataframeexprstring
import DataFrame
import Result

import DataFrame.Expr as Expr

-- Whitespace trimming (both sides)
...

Expr String Ops

dataframeexprstring
-- String operations with DataFrame.Expr
import DataFrame
import Result

import DataFrame.Expr as Expr
...

Expr String Transform

dataframeexprstring
-- String transformation chain
import DataFrame
import DataFrame.Expr exposing col
import Result

import DataFrame.Expr as Expr
...

Expr Symbol Col

dataframeexprsymbol
-- @name column references work directly with infix operators
import DataFrame
import Result

import DataFrame.Expr as Expr
...

Expr Type Cast

dataframeexprarithmetic
import DataFrame
import DataFrame.Expr exposing col
import Result

import DataFrame.Expr as Expr
...

Expr Window

dataframeexprwindow
import DataFrame
import Result

import DataFrame.Expr as Expr

let df =
...

Lineage Agg Origin

dataframelineageaggregation
import DataFrame
import DataFrame.Expr exposing col
import List

import DataFrame.Expr as Expr
...

Lineage Auto

dataframelineageprovenance
-- norun
-- Lineage appears automatically when printing a DataFrame
import DataFrame
import DataFrame.Expr as Expr
import Result
...

Lineage Byid

dataframelineageregistry
-- lineageById looks up a DataFrame in the lineage registry by its UUID
import DataFrame
import Maybe

let df =
    DataFrame.fromRecords
...

Lineage Byname

dataframelineageregistry
-- lineageByName searches the registry by name prefix, returns a list
import DataFrame
import List

-- lineageByName returns [Record] — empty list if no match
List.length (DataFrame.lineageByName "nonexistent-name")

Lineage Column

dataframelineage
-- norun
-- DataFrame.columnLineage returns origin info for a column
import DataFrame

let df = DataFrame.fromRecords [{ name = "Alice", age = 30 }]
...

Lineage Dag Join

dataframelineagedag
-- Join produces two parents in the DAG
import DataFrame
import List

let users =
    DataFrame.fromRecords
...

Lineage Full Record

dataframelineage
-- norun
-- Full lineage record structure
import DataFrame
import DataFrame.Expr as Expr
import Result
...

Lineage Global Ops

dataframelineage
-- norun
-- Global operations (filter, sort) are tracked separately
import DataFrame

let df =
    DataFrame.fromRecords
...

Lineage Join Origin

dataframelineagejoin
-- norun
-- Joined columns track their source DataFrame
import DataFrame

let users =
    DataFrame.fromRecords
...

Lineage Parents Derived

dataframelineagedag
-- Derived DataFrames track parent operations
import DataFrame
import List
import Result

let df =
...

Lineage Parents Root

dataframelineagedag
-- Root DataFrames have no parents
import DataFrame

let df = DataFrame.fromRecords [{ name = "Alice", age = 30 }]

DataFrame.parents df

Lineage Rename Origin

dataframelineage
-- norun
-- After rename, the transformation tracks the operation
import DataFrame
import Result

let df = DataFrame.fromRecords [{ name = "Alice", age = 30 }]
...

Lineage Sourcepath

dataframelineage
-- DataFrame.sourcePath returns Nothing for fromRecords
import DataFrame

let df =
    DataFrame.fromRecords
        [ { name = "Alice", age = 30 }
...

Lineage Tracking

dataframelineageprovenance
-- Track data transformation history
import DataFrame
import DataFrame.Expr as Expr
import Result

-- Create data and track transformations
...

Lineage Transformations

dataframelineage
-- norun
-- Columns track their transformation history
import DataFrame
import Result

let df =
...

Melt Reshape

dataframereshapemelt
-- melt reshapes wide data into long form by parsing column name prefixes
import DataFrame

-- Wide table: each measurement variable has one column per time point
let wide = DataFrame.fromRecords
    [ { nr = 1, var1_year1 = 10, var1_year2 = 20, var2_year1 = 5, var2_year2 = 8 }
...

Readcsv Columns

dataframereadCsvColumnsio
-- readCsvColumns reads only the specified columns from a CSV file
import DataFrame

case DataFrame.readCsvColumns [@name, @birth_date] "content/examples/guide/dataframe/dates.csv" of
    Ok df -> DataFrame.columns df
    Err _ -> []

Recode

dataframerecodelabels
-- Remap values with automatic label transfer
import DataFrame

let df =
    DataFrame.fromRecords
        [ { id = 1, score = 1 }
...

Value Labels

dataframelabelsvalue-labels
-- Attach value labels for coded variables
import DataFrame
import ValueLabelSet

let gender = ValueLabelSet.fromList [(1, "Male"), (2, "Female")]
...

Variable Labels

dataframelabelsmetadata
-- Variable labels for column descriptions
import DataFrame

let df =
    DataFrame.fromRecords
        [ { id = 1, gender = 1 }
...

Window Functions

dataframeanalyticswindow-functions
-- SQL-style window functions
import DataFrame

-- Sample sales data with rank column
DataFrame.fromRecords
    [ { product = "Laptop", revenue = 1200, rank = 1 }
...

Withcolumns Batching

dataframeexprapplyExprs
-- applyExprs batches exprs so later ones can reference columns added earlier
import DataFrame
import Result

import DataFrame.Expr as Expr
...

Dataframe Type Safety

Date

Datetime

Decimal

Duration

Error Handling

Arg Type Map

error-handling
import List

List.map 42 [1, 2, 3]

-- Error: Type mismatch: expected (a -> b), found Int
...

Arg Type String

error-handling
import String

String.length 42

-- Error: Type mismatch: expected String, found Int
...

Block Align

error-handling
if True then
    0
  else         -- Error: 'else' must align with 'if'
    1

Block Missing Indent

error-handling
fn greet : String -> String
fn greet name =
"Hello, " ++ name   -- Error: body must be indented by at least 4 spaces

Block Nest

error-handling
let x =
x + 1          -- Error: Block must be indented more than parent
               -- Hint: Indent the block to 4 spaces

Bool Correct

error-handling
let x = True

let y = False

x && y

Bool Error

error-handling
let x = true     -- Error: 'true' is not a Keel keyword
                 -- Hint: Use `True` for boolean true

Bounds Error

error-handling
let items = [1, 2, 3]

items[10]  -- Error: Index 10 out of bounds for list of size 3

Bounds Safe

error-handling
let items = [1, 2, 3]

items[0]  -- 1

Branch Correct

error-handling
let x = 2

case x of
    1 -> "one"
    2 -> "two"
    _ -> "other"

Branch Mismatch

error-handling
let x = 2

case x of
    1 -> 42  -- Int
    2 -> "hello"  -- Error: Case branches have incompatible types: Int and String
    _ -> 0

Constructor Type

error-handling
case Just 5 of
    Ok n -> n  -- Error: Pattern type mismatch: expected Maybe, but pattern is Result (Ok)
    _ -> 0

Converting Types

error-handling
import Result

-- Maybe to Result (with error message)
let a = Just 5 |> Result.fromMaybe "was nothing"

-- Result to Maybe (discards error)
...

Correct Syntax

error-handling
fn double : Int -> Int
fn double x =
    x * 2

-- Pattern matching uses case...of
...

Else Align

error-handling
let x = 10
let result =
    if x > 5 then "big"
        else "small"   -- Error: else must align with if

Enum Case

error-handling
enum Direction = North | south    -- Error: Enum variant must start with uppercase

Fn Missing Sig

error-handling
fn double x =        -- Error: missing type signature
    x * 2

Fuzzy Multiple

error-handling
import IO exposing print

let userName = "Alice"

let userAge = 30
...

Fuzzy Single

error-handling
import IO exposing print

let userName = "Alice"

let userAge = 30
...

Generic Annotation

error-handling
import Json

let data = Json.parse "{\"x\": 1}"

-- Error: Generic function result requires a type annotation for variable 'data'
...

Guard Correct

error-handling
let x = 5

case x of
    n if n > 0 -> "positive"
    n if n < 0 -> "negative"
    _ -> "zero"

Guard Type

error-handling
let x = 2

case x of
    n if n + 1 -> "bad"  -- Error: Guard expression must be Bool, found Int
    _ -> "ok"

Indent Error

error-handling
fn example : Int -> Int
fn example x =
let y = 1    -- Error: Function body must be indented by at least 4 spaces
    x + y

Js Record

error-handling
{ name: "Alice", age: 30 }
-- Error: JavaScript-style record syntax is not allowed
-- Hint: Use `=` instead of `:` for record field assignment
-- Example: `{ name = "Alice" }`

Json Fix

error-handling
import Json

let data : Result { x : Int } String = Json.parse "{\"x\": 1}"

data

Keywords

error-handling
return 5         -- Hint: Keel is expression-based; the last expression is the return value
match x of       -- Hint: Use `case ... of` for pattern matching
function add     -- Hint: Use `fn` to define functions
var x = 5        -- Hint: Use `let` for variable bindings

Maybe Correct

error-handling
let present = Just 42

let absent = Nothing

case present of
    Just n -> "Got a value"
...

Maybe Module

error-handling
import Maybe

-- Transform present values
let mapped = Just 5 |> Maybe.map (|x| x * 2)

-- Chain operations that might return Nothing
...

Mismatched Delim

error-handling
let x = [1, 2)
-- Error: Mismatched delimiter — '(' expected ')' but found ')'

Module Fn Typo

error-handling
import List
List.fold [1, 2, 3] 0
-- Error: Function 'fold' is not declared in module 'List'. Did you mean 'foldl' or 'foldr'?

Null Error

error-handling
let x = null     -- Error: 'null' is not a Keel keyword
                 -- Hint: Use `Nothing` for absent values

Pattern Type

error-handling
case 42 of
    "hello" -> 1  -- Error: Pattern type mismatch: expected Int, but pattern is String
    _ -> 0

Record Correct

error-handling
{ name = "Alice", age = 30 }

Result Module

error-handling
import Result

-- Transform success values
let mapped : Result Int String = Ok 5 |> Result.map (|x| x * 2)

-- Chain operations that might fail
...

Scope

error-handling
fn example : Int -> Int
fn example x =
    let inner = x + 1
    inner

inner  -- Error: Variable 'inner' is not in scope

Try Operator

error-handling
-- Unwrap Ok with ?, short-circuit on Err
let addOne = |x: Int| Ok (x + 1)
let result = 5 |> addOne
result?

Try Operator Err

error-handling
-- When ? is applied to Err, the result is Err (short-circuit)
let mayFail = |x: Int| Err "something failed"
let result = 5 |> mayFail
result?

Tuple Annotation

error-handling
let addPair = |(x, y): (Int, Int)| x + y
-- Error: Type annotations on tuple patterns must be on individual elements
-- Hint: Use `|(x: Int, y: Int)|` instead of `|(x, y): (Int, Int)|`.

Type Mismatch

error-handling
fn add : Int -> Int -> Int
fn add x y =
    x + y

add "hello" 5  -- Error: Expected Int but got String

Type Vs Alias

error-handling
enum Person = { name: String, age: Int }
-- Error: Expected enum variant, found record syntax
-- Hint: Use an inline record type annotation instead.

Unclosed Paren

error-handling
let x = (1 + 2
-- Error: Unclosed '(' — expected ')'

Undeclared

error-handling
let x = unknownVar    -- Error: Variable 'unknownVar' is not declared

Unexpected Delim

error-handling
let x = 1 + 2]
-- Error: Unexpected ']' — no matching '['

Variant Parens

error-handling
enum Result a e = Ok a | Err e
-- Result OkType ErrType: first parameter is success, second is error
-- Error: Enum variant 'Ok' appears to have data without parentheses
-- Hint: Use `Ok(a)` instead of `Ok a`. Variant data requires parentheses.

Functions

Arity Overloading 1

functions
module CustomMath exposing ..

    fn add : Int -> Int
    fn add x =
        x + 1
...

Arity Overloading 2

functions
module CustomMath exposing ..

    fn add : Int -> Int
    fn add x =
        x + 1
...

Common Filter

functions
import List

-- filter: keep matching elements
[1, 2, 3, 4] |> List.filter (|x| x > 2)

Common Fold

functions
import List

-- fold: reduce to single value
[1, 2, 3, 4] |> List.foldl (|acc x| acc + x) 0

Common Map

functions
import List

-- map: transform each element
[1, 2, 3] |> List.map (|x| x * 2)

Composition

functions
fn double : Int -> Int
fn double x =
    x * 2

fn addOne : Int -> Int
fn addOne x =
...

Currying

functions
fn add : Int -> Int -> Int
fn add x y =
    x + y

let add5 = add 5
...

Defining

functions
fn greet : String -> String
fn greet name =
    "Hello, " ++ name ++ "!"

greet "Alice"  -- "Hello, Alice!"

Duplicate Sig

functions
fn add : Int -> Int
fn add x = x + 1

fn add : Int -> Int
fn add x = x + 2

Factorial

functions
module CustomMath exposing factorial

    fn factorial : Int -> Int
    fn factorial n =
        if n <= 1 then
            1
...

Factorial Case

functions
fn factorial : Int -> Int
fn factorial n =
    case n of
        0 -> 1
        1 -> 1
        _ -> n * factorial (n - 1)
...

Fibonacci

functions
module CustomMath exposing fibonacci

    fn fibonacci : Int -> Int
    fn fibonacci n =
        if n <= 1 then
            n
...

Generic Assign

functions
import List

let doubled = List.map (|x| x * 2) [1, 2, 3]

let result =
    [1, 2, 3, 4, 5]
...

Generic Compose

functions
fn compose : (b -> c) -> (a -> b) -> a -> c
fn compose g f x =
    g (f x)

let double = |x : Int| x * 2
...

Generic Identity

functions
fn identity : a -> a
fn identity x =
    x

identity 42

Higher Order

functions
-- Takes a function as argument
fn applyTwice : (Int -> Int) -> Int -> Int
fn applyTwice f x =
    f (f x)

applyTwice (|x : Int| x + 1) 5  -- 7

Higher Order Context

functions
module M exposing ..

    fn apply : (Int -> Int) -> Int -> Int
    fn apply f x =
        f x
...

Lambda As Pattern

functions
let withAlias = |x : Int as m| (x, m)

withAlias 42

Lambda Basics

functions
let addOne = |x : Int| x + 1

let addTwo = |x : Int y : Int| x + y

let addTuple = |(x : Int, y : Int)| x + y
...

Lambda Body Inferred

functions
-- When the body constrains the parameter type, the annotation is optional.
-- Here x must be Int because x + 1 requires Int.
let f = |x| x + 1

f 1

Lambda Map

functions
import List

[1, 2, 3] |> List.map (|x| x * 2)

Lambda Multiline

functions
let compute =
    |x : Int|
        let y = 3
        x + y

compute 7

Lambda No Annotation

functions
|x| x

Lambda Record Fields

functions
let describe = |{ name: String, age: Int }| name

describe { name = "Alice", age = 30 }

Lambda Rest Pattern

functions
let getName = |{ name: String, .. }| name

getName { name = "Alice", age = 30 }

Lambda Tuple Add

functions
let addPair = |(x : Int, y : Int)| x + y

addPair (3, 4)

Lambda Typed

functions
let f1 = |x : Int| x + 1

let f2 = |x : Int y : Int| x + y

let f3 = |(x : Int, y : Int)| x + y
...

Lambda With Annotation

functions
let f = |x : Int| x + 1

f 1

Local Bindings

functions
import Math

fn quadraticFormula : Float -> Float -> Float -> (Float, Float)
fn quadraticFormula a b c =
    let discriminant = b * b - 4.0 * a * c
    let sqrtDisc =
...

Make Adder

functions
fn makeAdder : Int -> (Int -> Int)
fn makeAdder n =
    |x : Int| x + n

makeAdder 10 5

Native Pipes

functions
import List
import Math
import String

let a =
    "hello"
...

Overloaded Hof

functions
module Apply exposing ..

    fn apply : (Int -> Int) -> Int -> Int
    fn apply f x =
        f x
...

Overloading Int

functions
module CustomMath exposing ..

    fn double : Int -> Int
    fn double x =
        x * 2
...

Overloading String

functions
module CustomMath exposing ..

    fn double : Int -> Int
    fn double x =
        x * 2
...

Overloading Toplevel

functions
fn inc : Int -> Int
fn inc x =
    x + 1

fn inc : Float -> Float
fn inc x =
...

Pattern Matching Fn

functions
fn length : [a] -> Int
fn length list =
    case list of
        [] -> 0
        x :: xs -> 1 + length xs
...

Pipe Chain

functions
fn double : Int -> Int
fn double x =
    x * 2

fn addOne : Int -> Int
fn addOne x =
...

Pipe Operator

functions
-- Pipe operator provides context from the left operand
5 |> |x| x + 1

Pipeline Example

functions
import List

[1, 2, 3, 4, 5]
    |> List.filter (|x| x > 2)
    |> List.map (|x| x * 2)

Record Field Pipe

functions
-- Mixed typed and untyped fields (untyped inferred from context)
{ x = 1, y = 2 } |> |{ x: Int, y }| x + y

Stdlib Chained Inference

functions
import List

-- Type inference flows through chained operations
-- Each lambda's parameter type is inferred from the previous result
[1, 2, 3, 4, 5]
    |> List.filter (|x| x > 2)
...

Stdlib Filter Inference

functions
import List

-- Lambda parameter type inferred from List.filter signature
List.filter (|x| x > 2) [1, 2, 3, 4, 5]

-- [3, 4, 5]

Stdlib Foldl Inference

functions
import List

-- Accumulator and element types inferred from List.foldl signature
-- foldl : (b -> a -> b) -> b -> List a -> b
-- With initial value 0 (Int) and List Int, acc : Int and x : Int
List.foldl (|acc x| acc + x) 0 [1, 2, 3, 4]
...

Stdlib Map Inference

functions
import List

-- Lambda parameter type inferred from List.map signature
List.map (|x| x * 2) [1, 2, 3]

-- [2, 4, 6]

Stdlib Zipwith Inference

functions
import List

-- Both parameters inferred from List.zipWith signature
-- zipWith : (a -> b -> c) -> List a -> List b -> List c
-- With List Int and List Int, both x : Int and y : Int
List.zipWith (|x y| x * y) [1, 2, 3] [4, 5, 6]
...

Tuple Arg Fst

functions
fn fst : (Int, String) -> Int
fn fst pair =
    case pair of
        (x, _) -> x

fst (42, "hello")

Tuple Arg Swap

functions
fn swap : (a, b) -> (b, a)
fn swap pair =
    case pair of
        (x, y) -> (y, x)

swap (1, "hello")

Type Signatures

functions
fn add : Int -> Int -> Int
fn add x y =
    x + y

add 3 4  -- 7

Getting Started

Http

Indentation

Basic Blocks

indentation
-- Function body must be indented
fn addOne : Int -> Int
fn addOne x =
    x + 1

addOne 5  -- 6

Case Indentation

indentation
-- Case branches must be indented from 'case'
let value = 2

let result =
    case value of
        1 -> "one"
...

Case Multiline Body

indentation
-- Case branch bodies can span multiple lines
let value = 2

let result =
    case value of
        1 ->
...

Continuation Argument

indentation
-- Multiline arguments work with COLLECTIONS (lists, records, tuples)

-- NOT with simple values like integers

import List
...

If Multiline

indentation
-- If-then-else with multiline expressions
let condition = True

let result =
    if condition then
        1 + 2
...

Let Block

indentation
-- Multiple let bindings at same indentation form a block
fn compute : Int -> Int
fn compute x =
    let a = x + 1
    let b = a * 2
    let c = b - 3
...

List Multiline

indentation
-- Lists can span multiple lines (Elm-style)
import List

let numbers = [1, 2, 3, 4, 5]

List.sum numbers
...

Local Fn Args

indentation
fn add : Int -> Int -> Int
fn add x y =
    x + y

let result = add 1 2
...

Multiline Function Call

indentation
-- Multi-line function calls work with collections on new lines
import List

-- Lambda on same line, list on indented new line
let doubled = List.map (|x| x * 2) [1, 2, 3]
...

Multiline Module Args

indentation
import List

List.map (|x| x * 2) [1, 2, 3]

Pipe Multiline

indentation
-- Pipes work naturally with multiline formatting
import List

let result =
    [1, 2, 3, 4, 5]
        |> List.map (|x| x * 2)
...

Record Multiline

indentation
-- Records can span multiple lines (Elm-style)
let person =
    { name = "Alice"
    , age = 30
    , city = "Paris"
    }
...

Scope Nested

indentation
-- Indentation creates nested scopes within a block
fn example : Int -> Int
fn example x =
    let a = x + 1
    let b = a * 2
    let c = a + b
...

Scope Rules

indentation
fn example : Int -> Int
fn example n =
    let a = n + 1
    let b = a * 2
    let c = a + b
    c
...

Separate Expressions

indentation
-- Lines at the SAME indentation are separate expressions
let x = 1

let y = 2

let z = 3
...

Landing

Lexical

Matrix

Modules

Access Add

modules
module CustomMath exposing add, multiply

    fn add : Int -> Int -> Int
    fn add x y =
        x + y
...

Access Multiply

modules
module CustomMath exposing multiply

    fn multiply : Int -> Int -> Int
    fn multiply x y =
        x * y
...

Exposing

modules
-- norun
-- Expose specific items
module exposing functionA, functionB, TypeA

-- Expose all
module exposing ..
...

Fibonacci

modules
module CustomMath exposing fibonacci

    fn fibonacci : Int -> Int
    fn fibonacci n =
        if n <= 1 then
            n
...

File Level

modules
module exposing createUser, getName

fn createUser : String -> Int -> { name: String, age: Int }
fn createUser name age = { name = name, age = age }

fn getName : { name: String, age: Int } -> String
...

Geometry Area

modules
import Math

module Geometry exposing Shape, area, perimeter

    enum Shape
        = Circle(Float)
...

Geometry Perimeter

modules
module Geometry exposing perimeter

    fn perimeter : Float -> Float
    fn perimeter r =
        2.0 * 3.14159 * r
...

Import Alias Exposing

modules
import List as L exposing length

length [1, 2]

Import Aliases

modulesimportsaliases
import List as L
-- Modules and import aliases
import Math as M

M.abs (L.length [1, 2, 3])

Import Exposing

modules
import List exposing map

-- Using built-in list functions directly
[1, 2, 3] |> map (|x| x * 2)  -- [2, 4, 6]

Import Exposing Bare

modules
import List exposing map, filter

map (|x : Int| x + 1) [1, 2, 3]

Indent Correct

modules
module CustomMath exposing add

    fn add : Int -> Int -> Int
    fn add x y =
        x + y
...

Indent Error

modules
-- Error: Inline module content must be indented
module CustomMath exposing add

fn add x y = x + y    -- Wrong: not indented

Inline

modules
module CustomMath exposing add, multiply

    fn add : Int -> Int -> Int
    fn add x y =
        x + y
...

Math Module

modules
-- norun

module exposing double, square

fn double : Int -> Int
fn double x = x * 2
...

Recursive

modules
module CustomMath exposing factorial, fibonacci

    fn factorial : Int -> Int
    fn factorial n =
        if n <= 1 then
            1
...

Shadowing Math

modules
module Math exposing double

    fn double : Int -> Int
    fn double x =
        x * 2
...

Shapes Enum Module

modules
module Shapes exposing Shape, area

    enum Shape
        = Circle(Float)
        | Square(Float)
...

Stdlib Qualified

modules
import Json
import List
import Maybe
import Result
import String
...

Uses Stdlib

modules
-- norun

module exposing greeting

import String
...

Operators

Arithmetic

operators
let addition = 5 + 3

let subtraction = 10 - 4

let multiply = 6 * 7
...

Comparison

operators
let eq = 5 == 5

let neq = 5 != 6

let lt = 3 < 5
...

Compose Backward

operators
-- Backward composition (g first, then f)
let addOne = |x : Int| x + 1

let double = |x : Int| x * 2

let doubleThenAdd = addOne << double
...

Compose Forward

operators
-- Forward composition (f first, then g)
let addOne = |x : Int| x + 1

let double = |x : Int| x * 2

let addThenDouble = addOne >> double
...

Division

operators
let floatDiv = 10 / 3

let intDiv = 10 // 3

(floatDiv, intDiv)

List Ops

operators
-- Cons (prepend element)
let consed1 = 1 :: [2, 3]

let consed2 : [Int] = 1 :: (2 :: [])

-- Concatenation
...

Logical

operators
-- And (both must be True)
let and1 = True && True

let and2 = True && False

-- Or (at least one must be True)
...

Pipe Forward

operators
fn double : Int -> Int
fn double x =
    x * 2

fn addOne : Int -> Int
fn addOne x =
...

Pipeline

operators
import List

-- Pipeline example
[1, 2, 3, 4, 5]
    |> List.filter (|x| x > 2)
    |> List.map (|x| x * 2)
...

Short Circuit

operators
-- False && ... returns False immediately without evaluating the right side
let result = False && True

result  -- False

String Concat

operators
"Hello, " ++ "World!"

Try Operator

operators
-- ? unwraps Ok values and short-circuits on Err
let addOne = |x: Int| Ok (x + 1)
let result = 5 |> addOne
result?

Type Promotion

operators
let x = 1 + 2.5

let y = 3 * 1.5

x + y

Pattern Matching

As Pattern

pattern-matching
let maybe = Just 42

case maybe of
    Just x -> (x, Just x)
    Nothing -> (0, Nothing)

As Pattern List

pattern-matching
let list = [1, 2, 3]

case list of
    x :: xs as all -> "Head"
    [] -> "empty"

Branch Mismatch

pattern-matching
case 1 of
    1 -> 42  -- Int
    2 -> "hello"  -- Error: Case branches have incompatible types
    _ -> 0

Cons

pattern-matching
let list = [1, 2, 3]

case list of
    x :: xs -> x  -- x is the head, xs is the tail
    [] -> 0  -- empty list case

Constructor

pattern-matching
let maybeValue = Just 42

case maybeValue of
    Just x -> "Got value"
    Nothing -> "Nothing"

Exhaustive

pattern-matching
enum TrafficLight = Red | Yellow | Green

let light = TrafficLight::Yellow

case light of
    TrafficLight::Red -> "stop"
...

Fn Nested

pattern-matching
fn addPairs : (Int, Int) -> (Int, Int) -> (Int, Int)
fn addPairs p1 p2 =
    case (p1, p2) of
        ((x1, y1), (x2, y2)) -> (x1 + x2, y1 + y2)

addPairs (1, 2) (3, 4)  -- (4, 6)

Fn Pattern

pattern-matching
fn fst : (a, b) -> a
fn fst pair =
    case pair of
        (x, _) -> x

fst
...

Guard Exhaustive

pattern-matching
let x = 0

case x of
    n if n > 0 -> "positive"
    n if n < 0 -> "negative"
    _ -> "zero"

Guards

pattern-matching
let number = 42

case number of
    n if n < 0 -> "negative"
    n if n == 0 -> "zero"
    n if n < 10 -> "small positive"
...

Lambda Record

pattern-matching
-- Record destructuring
let describe = |{ name: String, age: Int }| name

describe { name = "Bob", age = 25 }

Lambda Tuple

pattern-matching
-- Tuple destructuring
let addPair = |(x : Int, y : Int)| x + y

addPair (3, 4)  -- 7

Let Record

pattern-matching
let user = { name = "Alice", age = 30 }

let { name, age } = user

name

Let Tuple

pattern-matching
let point = (10, 20)

let (x, y) = point

x + y

List Exact

pattern-matching
let list = [1, 2]

case list of
    [] -> "empty"
    [x] -> "single"
    [x, y] -> "pair"
...

Literal

pattern-matching
let x = 1

case x of
    0 -> "zero"
    1 -> "one"
    _ -> "many"

Multi Cons

pattern-matching
let list = [1, 2, 3, 4]

case list of
    a :: b :: rest -> a + b
    x :: xs -> x
    [] -> 0

Nested

pattern-matching
import String

let result = Ok Just 5

case result of
    Ok (Just x) -> "Success with value: " ++ String.fromInt x
...

Or Binding

pattern-matching
let point = (5, 2)

case point of
    (x, 1) | (x, 2) | (x, 3) -> x  -- x is bound in all alternatives
    _ -> 0

Or Pattern

pattern-matching
enum Direction
    = North
    | South
    | East
    | West
...

Qualified Enum

pattern-matching
enum Color = Red | Green | Blue

let color = Color::Green

case color of
    Color::Red -> "fire"
...

Record

pattern-matching
let person = { name = "Alice", age = 30 }

case person of
    { name, age } -> name

Record Rest

pattern-matching
let user =
    { name = "Bob"
    , age = 25
    , email = "bob@example.com"
    }
...

Recursive

pattern-matching
fn sum : [Int] -> Int
fn sum numbers =
    case numbers of
        [] -> 0
        x :: xs -> x + sum xs
...

Tuple

pattern-matching
let pair = (3, 0)

case pair of
    (0, 0) -> "origin"
    (x, 0) -> "on x-axis"
    (0, y) -> "on y-axis"
...

Type Mismatch

pattern-matching
case 42 of
    "hello" -> 1  -- Error: Pattern type mismatch: expected Int, but pattern is String
    _ -> 0

Type Unify

pattern-matching
let x = 2

case x of
    1 -> 42  -- Int
    2 -> 3.14  -- Float: compatible, unifies to Float
    _ -> 0

Unreachable

pattern-matching
let x = False

case x of
    _ -> "anything"  -- This matches everything
    True -> "true"  -- Warning: Unreachable pattern

Variable

pattern-matching
let point = (3, 4)

case point of
    (x, y) -> x + y

Variant Patterns

pattern-matchingenums
enum Shape = Circle(Float) | Rect { width : Float, height : Float }

let s = Shape::Rect { width = 2.0, height = 2.5 }

case s of
    Circle r               -> r
...

Wildcard

pattern-matching
let tuple = (42, "ignored")

case tuple of
    (x, _) -> x  -- Ignore second element

Process

Runtime Errors

Table

Time

Types

03b Record Newtype

types
type Person = { name: String, age: Int }

let p = Person { name = "Alice", age = 30 }

case p of
    Person { name } -> name

03c Tuple Newtype

types
type Pair = (Int, String)

let p = Pair (1, "x")

case p of
    Pair (n, _) -> n

Alias Resolved

types
-- norun
-- UserId and PostId are distinct types — not interchangeable
type UserId = Int
type PostId = Int

fn greet : UserId -> String
...

Bool Int Error

types
True + 1

Bracket List All

types
let numbers : [Int] = [1, 2, 3]

let names : [String] = ["Alice", "Bob"]

let nested : [[Int]] = [[1, 2], [3, 4]]
...

Case Pattern

types
-- Case expression patterns
case (42, "test") of
    (x, y) -> y

Compound

types
-- List of integers
let numbers =
    [1, 2, 3]
    -- Tuple

let pair = (42, "answer")
...

Decimal Type

types
let price = 19.99d

let tax = 0.07d

let total = price + price * tax
...

Generic Pair

types
enum Pair a b = Pair(a, b)

let p = Pair::Pair (1, "hello")

p

Generic Tree

types
enum Tree a
    = Leaf(a)
    | Node(Tree a, a, Tree a)

let tree : Tree Int =
    Tree::Node (Tree::Leaf 1, 2, Tree::Node (Tree::Leaf 3, 4, Tree::Leaf 5))
...

Hof Context

types
-- Higher-order function context
import List

-- Higher-order function context
[1, 2, 3] |> List.map (|x| x * 2)
...

Inference

types
let x = 42  -- Inferred as Int

let name = "Alice"  -- Inferred as String

let ratio = 3.14  -- Inferred as Float
...

Inference Annotation

types
import List

let empty : [Int] = []  -- Needed: can't infer element type

List.length empty

Json Parse Annotation

types
import Json

let data : Result { name : String } String = Json.parse "{\"name\": \"Alice\"}"

data

Lambda Annotation

types
(|x : Int| x + 1) 1

Lambda Pattern

types
-- Lambda parameter patterns with context
(1, 2) |> |(a, b)| a + b

Maybe Type

types
-- norun
enum Maybe a = Just(a) | Nothing

Maybe Usage

types
let present = Just 42

let absent = Nothing

case present of
    Just n -> "Got a value"
...

Multiline Enum

types
enum Direction
    = North
    | South
    | East
    | West
...

Numeric Promotion

types
let x = 1 + 2.5

let y = 3 * 1.5

x + y

Open Record Alias

types
let p : { name : String, age : Int, .. } =
    { name = "Alice"
    , age = 30
    , email = "a@b.com"
    }
...

Open Record Dataframe

types
import DataFrame

-- Open record type allows extra fields

let data : DataFrame { name : String, age : Int, .. } =
    DataFrame.fromRecords
...

Parameterized Alias

types
type Validated a = a

let score : Validated Int = Validated 99

case score of
    Validated n -> n

Parenthesized All

types
let x : Result (Maybe Int) String = Ok Just 5

let y : Maybe [Int] = Just [1, 2, 3]

let z : [Maybe Int] =
    [ Just 1
...

Pipe Context

types
-- Pipe operator provides context
5 |> |x| x + 1

Primitives

types
let x = 42

let pi = 3.14

let active = True
...

Record Type

types
let user : { id : Int, name : String, email : String, active : Bool } =
    { id = 1
    , name = "Alice"
    , email = "alice@example.com"
    , active = True
    }
...

Recursive

types
enum MyList a = Nil | Cons(a, MyList a)

let nums =
    MyList::Cons (1, MyList::Cons (2, MyList::Cons (3, MyList::Nil)))

nums

Result Err

types
let failure = Err "something went wrong"

case failure of
    Ok value -> "Success"
    Err msg -> "Error: " ++ msg

Result Ok

types
let success = Ok 42

case success of
    Ok value -> "Success"
    Err msg -> "Error: " ++ msg

Result Type

types
-- norun
enum Result a e = Ok(a) | Err(e)

Shape Construction

types
enum Shape
    = Circle(Float)
    | Rectangle(Float, Float)

Shape::Rectangle (10.0, 20.0)

Simple Enum

types
enum Direction
    = North
    | South
    | East
    | West
...

Symbol Basic

typessymbol
[:north, :south, :east]

Symbol Equality

typessymbolequality
[:north == :north, :north == :south]

Symbol Field Names

typesrecordsdataframe
-- norun

-- Symbol field names in type annotations let you reference columns
-- whose names don't conform to lowercase identifier syntax.
-- This is most useful for DataFrame schemas from external data sources:
...

Symbol Pattern

typessymbolpattern-matching
let dir = :north

case dir of
    :north -> "going up"
    :south -> "going down"
    _ -> "going sideways"

Symbol Quoted

typessymbol
:"hello world"

Tuple Destructure

types
-- Tuple destructuring
let pair = (1, "hello")

let (x, y) = pair  -- x: Int, y: String

y

Type Alias

types
type UserId = Int

let id = UserId 42

case id of
    UserId n -> n

Type Alias All

types
let x : Result { name : String, age : Int } String = Ok { name = "Alice", age = 30 }

let y : Maybe { name : String, age : Int } = Just { name = "Bob", age = 25 }

let z : [{ name : String, age : Int }] = [{ name = "Alice", age = 30 }]
...

Type Alias Fn Arg

type-aliastypesfunctions
type alias Person = { name : String, age : Int }

fn greet : { name : String, .. } -> String
fn greet p = p.name

let alice : Person = { name = "Alice", age = 30 }
...

Type Alias Parameterized

type-aliastypesgenerics
type alias Box a = { value : a }

let b : Box Int = { value = 42 }
b.value

Type Alias Record

type-aliastypesrecords
type alias Person = { name : String, age : Int }

let p : Person = { name = "Alice", age = 30 }
p.age

Type Alias Scalar

type-aliastypes
type alias UserId = Int

let id : UserId = 42
id + 1

Type Alias Vs Newtype

type-aliasnewtypetypes
-- type alias: transparent — a plain record satisfies the annotation
type alias PersonAlias = { name : String, age : Int }

let a : PersonAlias = { name = "Alice", age = 30 }
a.name

Using Enum

types
enum Direction
    = North
    | South
    | East
    | West
...

Value Label Enum

typesenumvalue-label
-- Define an enum with ValueLabel data
-- Construct and match on ValueLabel variants
enum Gender
    = Male(ValueLabel 1 "Male")
    | Female(ValueLabel 2 "Female")
    | Other(ValueLabel 3 "Other")
...

Value Label Fromtype

typesenumvalue-label
-- Generate a ValueLabelSet from a ValueLabel enum
import ValueLabelSet

enum Gender
    = Male(ValueLabel 1 "Male")
    | Female(ValueLabel 2 "Female")
...

Variant Data Circle

types
enum Shape
    = Circle(Float)
    | Rectangle(Float, Float)

fn area : Shape -> Float
fn area shape =
...

Variant Data Rect

types
enum Shape
    = Circle(Float)
    | Rectangle(Float, Float)

fn area : Shape -> Float
fn area shape =
...

Variant Record

types
enum User
    = Guest
    | Member { name : String, id : Int }

let user = User::Member { name = "Alice", id = 42 }
...

Valuelabel

Valuelabelset

Variables