Esc
Start typing to search...

Code Examples

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

253 examples

Basics

Collections

Building Lists

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

let list2 =
...

Filter

collections
-- Filter: keep matching elements
import List

[ 1
, 2
, 3
...

Fold

collections
-- Fold: reduce to single value
import List

[ 1
, 2
, 3
...

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 =
...

List Pattern

collections
let list =
    [1, 2, 3]

case list of
    [] -> "empty"
    [x] -> "single element"
...

Lists

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

Map

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

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

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" }

case user of
    { name, .. } -> "Hello, " ++ name

Record Update

collections
-- Record update syntax

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

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

Record Workflow

collections
let user =
    { name = "Eve", age = 28 }
    -- Update fields (creates new record)

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

Records

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

user.name

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
type Color = Red | Green | Blue

let color = Color::Green

let description =
    case color of
...

Catchall

control-flow
type Color = Red | Green | Blue

let color = Green

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

Else If

control-flow
let score = 85

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

Exhaustive

control-flow
type Color = Red | Green | Blue

let color = Blue

case color of
    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 condition then 1 else "zero"  -- Error: type mismatch

List Pattern

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

case numbers of
    [] -> "empty list"
    [x] -> "single element"
...

Maybe Handling

control-flow
let maybeUser = Just "Alice"

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

Maybe Type

control-flow
type Maybe a = Just a | Nothing

Multiple Head

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

Nested Match

control-flow
let data = (3, 4)

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

Or Patterns

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

Recursive Sum

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

Result Handling

control-flow
let parseResult = Ok 42

case parseResult of
    Ok n    -> "Parsed: " ++ show n
    Err msg -> "Error: " ++ msg

Result Type

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

Dataframe

Expr Aggregation

dataframeexpraggregation
-- Aggregation with DataFrame.Expr
import DataFrame
import DataFrame.Expr as Expr

DataFrame.fromRecords
    [ { value = 10 }
...

Expr Basics

dataframeexprexpressions
-- DataFrame.Expr for composable column operations
import DataFrame
import DataFrame.Expr as Expr

DataFrame.fromRecords
    [ { name = "Alice", revenue = 100 }
...

Expr Conditional

dataframeexprconditional
-- Conditional expressions with DataFrame.Expr
import DataFrame
import DataFrame.Expr as Expr

DataFrame.fromRecords
    [ { name = "Alice", score = 95 }
...

Expr String Ops

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

DataFrame.fromRecords
    [ { name = "alice" }
...

Lineage Tracking

dataframelineageprovenance
-- Track data transformation history
import DataFrame

-- Create data and track transformations
DataFrame.fromRecords [{ product = "Laptop", revenue = 1200 }, { product = "Phone", revenue = 800 }]
    |> DataFrame.filterGt "revenue" 700
...

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 and window functions
DataFrame.fromRecords [{ product = "Laptop", revenue = 1200 }, { product = "Phone", revenue = 800 }]
    |> DataFrame.withColumn "rank" [1, 2]
...

Date

Datetime

Decimal

Duration

Error Handling

Block Align

error-handling
if condition then
    result1
  else         -- Error: 'else' must align with 'if'
    result2

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
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

Correct Syntax

error-handling
fn double: Int -> Int
fn double x =
    x * 2
    -- Pattern matching uses case...of

let value = Just 5
...

Enum Case

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

Fuzzy Multiple

error-handling
let userName = "Alice"
let userAge = 30
let userEmail = "alice@example.com"
print usrNme
-- Error: Variable 'usrNme' is not declared. Did you mean 'userName', 'userAge', or 'userEmail'?

Fuzzy Single

error-handling
let userName = "Alice"
let userAge = 30
print usrName
-- Error: Variable 'usrName' is not declared. Did you mean 'userName'?

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
case x of
    n if n + 1 -> "bad"    -- Error: Guard expression must be Bool, found Int
    _ -> "ok"

Indent Error

error-handling
fn example x =
let y = 1    -- Error: Expected indentation of 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" }`

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 Types

error-handlingmayberesult
-- Safe error handling with Maybe
import List

import Maybe

-- Extract values with default fallback
...

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 }

Scope

error-handling
let x =
    let inner = 5
    inner
print inner    -- Error: Variable 'inner' is not in scope

Type Mismatch

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

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

Undeclared

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

Functions

Arity Overloading 1

functions
module Math exposing (..)

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

Arity Overloading 2

functions
module Math exposing (..)

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

Defining

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

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

Factorial

functions
fn factorial: Int -> Int
fn factorial n =
    if n <= 1 then
        1
    else
        n * factorial (n - 1)
...

Factorial Case

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

Fibonacci

functions
fn fibonacci: Int -> Int
fn fibonacci n =
    if n <= 1 then
        n
    else
        fibonacci (n - 1) + fibonacci (n - 2)
...

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
...

Overloaded Hof

functions
module Apply exposing (..)

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

Overloading Int

functions
module Math exposing (..)

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

Overloading String

functions
module Math 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 =
...

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

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
...

Stdlib Filter Inference

functions
import List

-- Lambda parameter type inferred from List.filter signature
List.filter (|x| x > 2)

[ 1
...

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)
...

Stdlib Map Inference

functions
import List

-- Lambda parameter type inferred from List.map signature
List.map (|x| x * 2)

[1, 2, 3]
...

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)
...

Type Signatures

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

add 3 4  -- 7

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"
    2 -> "two"
...

Case Multiline Body

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

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

Continuation Argument

indentation
-- Multiline arguments work with COLLECTIONS (lists, records, tuples)
-- NOT with simple values like integers

import List

-- This works: list on new indented line continues as argument
...

If Multiline

indentation
-- If-then-else branches with multiline bodies
let condition = True

let result =
    if condition then
        let a = 1
...

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
...

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
...

Pipe Multiline

indentation
-- Pipes work naturally with multiline formatting
import List

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

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      -- 'a' is visible here
    let c = a + b      -- both 'a' and 'b' are visible
...

Separate Expressions

indentation
-- Lines at the SAME indentation are separate expressions
let x = 1
let y = 2
let z = 3

-- Each let is a separate statement, evaluated in sequence
...

Landing

Modules

Access Add

modules
module Math exposing (add, multiply)

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

Access Multiply

modules
module Math exposing (multiply)

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

Exposing

modules
-- Expose specific items
module exposing (functionA, functionB, TypeA)

-- Expose all
module exposing (..)
...

Fibonacci

modules
module Math exposing (fibonacci)

    fn fibonacci: Int -> Int
    fn fibonacci n =
        if n <= 1 then n
        else fibonacci (n - 1) + fibonacci (n - 2)
...

File Level

modules
module exposing (User, createUser, getName)

type alias User = { name: String, age: Int }

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

Geometry Area

modules
module Geometry exposing (Shape, area, perimeter)

    import Math

    type Shape = Circle(Float) | Rectangle(Float, Float) | Triangle(Float, Float, Float)
...

Geometry Perimeter

modules
module Geometry exposing (perimeter)

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

Import

modules
import String

Import Alias

modules
import Math as Something

Import Aliases

modulesimportsaliases
-- Modules and import aliases
import Math as M

import List as L

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]

Indent Correct

modules
module Math exposing (add)

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

Indent Error

modules
-- Error: Inline module content must be indented
module Math exposing (add)

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

Inline

modules
module Math exposing (add, multiply)

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

Recursive

modules
module Math exposing (factorial, fibonacci)

    fn factorial: Int -> Int
    fn factorial n =
        if n <= 1 then 1
        else n * factorial (n - 1)
...

Operators

Pattern Matching

As Pattern

pattern-matching
let maybe = Just 42

case maybe of
    Just x as original -> (x, original)
    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 x 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
type 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
...

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"
...

Literal

pattern-matching
let x = 1

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

Multi Cons

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

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
type Direction
    = North
    | South
    | East
    | West
...

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" }

case user of
    { name, .. } -> "Hello, " ++ name

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

Wildcard

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

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

Table

Time

Types

Alias Resolved

types
type alias UserId = Int

let x = 42  -- UserId resolves to Int

let y = x  -- Compatible: UserId is Int
...

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")
...

Dataframe Schemas

typesdataframetype-safety
-- Compile-time schema validation
import DataFrame

-- Create typed data
DataFrame.fromRecords [{ name = "Alice", age = 30 }, { name = "Bob", age = 25 }]
    |> DataFrame.select ["name", "age"]
...

Generic Pair

types
type Pair a b = Pair a b

let p = Pair 1 "hello"
p

Generic Tree

types
type Tree a
    = Leaf a
    | Node (Tree a) a (Tree a)

let tree: Tree Int =
    Node
...

Hof Context

types
-- Higher-order function context
[1, 2, 3] |> map (|x| x * 2)  -- x inferred as Int from list context

Inference

types
let x = 42  -- Inferred as Int

let name = "Alice"  -- Inferred as String

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

Inference Annotation

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

Lambda Annotation

types
|x| x + 1

|x: Int| x + 1

Lambda Pattern

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

Maybe Type

types
type 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
type Direction
    = North
    | South
    | East
    | West
...

Numeric Promotion

types
let x = 1 + 2.5

let y = 3 * 1.5

x + y

Parameterized Alias

types
type alias Container a = { value: a }

let intBox =
    { value = 42 }

intBox.value

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
type alias User = {
    id: Int,
    name: String,
    email: String,
    active: Bool
}
...

Recursive

types
type MyList a = Nil | Cons a (MyList a)

let nums = Cons 1 (Cons 2 (Cons 3 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
type Result a e = Ok a | Err e

Simple Enum

types
type Direction = North | South | East | West

let heading = North
heading

Tuple Destructure

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

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

y

Type Alias

types
type alias Name = String

type alias Age = Int

let userName = "Bob"
...

Using Enum

types
type Direction = North | South | East | West

let favorite: Direction = North

case favorite of
    North -> "Going up"
...

Variant Data Circle

types
type Shape
    = Circle Float
    | Rectangle Float Float

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

Variant Data Rect

types
type Shape
    = Circle Float
    | Rectangle Float Float

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

Variant Record

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

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

Valuelabelset

Variables