Code Examples
Explore Keel through practical code examples. Click any example to open it in the playground.
437 examples
Basics
Comments
-- This is a line comment
{- This is a
block comment -}
let x = 42 -- inline comment...
Doc Comment
{-| Increments a number by one. -}
fn inc : Int -> Int
fn inc x =
x + 1
inc 1Functions
fn add : Int -> Int -> Int
fn add x y =
x + y
add 2 3 -- Returns 5If Indentation
let condition = True
if condition then
"result1"
else
"result2" -- Must align with 'result1'Indentation
fn example : Int -> Int
fn example x =
let y = 1 -- Block must be indented
x + y
example 5Inline Module
module CustomMath exposing add
fn add : Int -> Int -> Int
fn add x y =
x + y
...
Operators
-- Arithmetic
let sum = 1 + 2
let diff = 5 - 3
let prod = 4 * 2...
Shadowing
let x = 1
let x = x + 1
xValues Types
-- Numbers
let intVal = 42 -- Int
let floatVal = 3.14 -- Float
let price = 19.99d -- Decimal (exact precision)...
Variables
let x = 42
let name = "Alice"
let pi = 3.14159
...
Collections
Bracket List
let xs : [Int] = [1, 2, 3]
let ys : [Int] = [4, 5, 6]
ysBuilding Lists
-- Prepend element
let list1 =
1 :: [2, 3]
-- Concatenate lists
let list2 = [1, 2] ++ [3, 4]...
Dataframe Fromrecords
import DataFrame
DataFrame.fromRecords
[ { name = "Alice", score = 95 }
, { name = "Bob", score = 87 }
, { name = "Charlie", score = 92 }...
Filter
-- Filter: keep matching elements
import List
[1, 2, 3, 4] |> List.filter (|x| x > 2)
-- [3, 4]Fold
-- Fold: reduce to single value
import List
[1, 2, 3, 4] |> List.foldl (|acc x| acc + x) 0
-- 10Length
import List
fn length : [a] -> Int
fn length list =
case list of
[] -> 0...
List Access
let items = [10, 20, 30]
items[0]List Ops
-- Prepend (cons)
let consed =
1 :: [2, 3]
-- Concatenation
let joined = [1, 2] ++ [3, 4]...
List Pattern
let list = [1, 2, 3]
case list of
[] -> "empty"
[x] -> "single element"
x :: xs -> "has multiple elements"List Statistics
-- List statistics: mean, median, variance, std, percentile, mode
import List
import Maybe
-- Integer list statistics
let scores = [60, 70, 80, 90, 100]...
Lists
let numbers = [1, 2, 3, 4, 5]
let names = ["Alice", "Bob", "Charlie"]
let empty : [Int] = []
...
Map
-- Map: transform each element
import List exposing map
[1, 2, 3] |> map (|x| x * 2) -- [2, 4, 6]Multiline List
let users =
[ { name = "Alice", age = 30 }
, { name = "Bob", age = 25 }
, { name = "Charlie", age = 35 }
]
...
Multiline Record
let config =
{ host = "localhost"
, port = 8080
, debug = True
, maxConnections = 100
}...
Nested Record
let data =
{ user = { profile = { name = "Alice" } }
}
data.user.profile.nameRecord Access
let user = { name = "Alice", age = 30 }
user.nameRecord Destructure
let person = { name = "David", age = 40 }
let { name, age } = person
nameRecord Multi Update
let person = { name = "Alice", age = 30 }
let updated = { person | age = 31, name = "Alicia" }
updated.nameRecord Pattern
let person = { name = "Bob", age = 25 }
case person of
{ name, age } -> nameRecord Rest
let user =
{ name = "Carol"
, age = 35
, email = "carol@example.com"
}
...
Record Update
-- Record update syntax
let person = { name = "Alice", age = 30 }
let older = { person | age = 31 }
...
Record Workflow
-- Record update creates a new record
let user = { name = "Eve", age = 28 }
let updatedUser = { user | age = user.age + 1 }
updatedUser.nameRecords
let user =
{ name = "Alice"
, age = 30
, email = "alice@example.com"
}
...
Reverse
import List
fn reverse : [a] -> [a]
fn reverse list =
case list of
[] -> []...
Tuple Access
let pair = (1, "hello")
let first = pair.0 -- 1
let second = pair.1 -- "hello"
...
Tuple Access 2
let triple = (True, 42, "world")
triple.2Tuple Destructure
let (x, y) = (10, 20)
x + yTuple Pattern
let pair = (3, 0)
case pair of
(0, 0) -> "origin"
(x, 0) -> "on x-axis"
(0, y) -> "on y-axis"...
Tuples
let pair = (1, "one")
let triple = (True, 42, "hello")
let point = (3.5, 4.2)
...
Control Flow
Case Enum
enum Color = Red | Green | Blue
let color = Color::Green
let description =
case color of...
Catchall
enum Color = Red | Green | Blue
let color = Color::Green
case color of
Color::Red -> "primary"...
Else If
let score = 85
let grade =
if score >= 90 then
"A"
else if score >= 80 then...
Exhaustive
enum Color = Red | Green | Blue
let color = Color::Blue
case color of
Color::Red -> "red"...
Guard Exhaustive
let x = 0
case x of
n if n > 0 -> "positive"
n if n < 0 -> "negative"
_ -> "zero"Guards
let number = -5
case number of
n if n < 0 -> "negative"
n if n == 0 -> "zero"
n if n > 0 -> "positive"...
If Expression
let x = 5
let result =
if x > 0 then
"positive"
else...
If Multiline
let condition = True
if condition then
"yes"
else
"no"If Same Type
let condition = True
-- Valid: both branches return Int
if condition then
1
else...
If Type Mismatch
if False then
1
else
"zero" -- Error: type mismatchList Pattern
let numbers = [1, 2, 3]
case numbers of
[] -> "empty list"
[x] -> "single element"
[x, y] -> "two elements"...
Maybe Handling
let maybeUser = Just "Alice"
let displayName =
case maybeUser of
Just name -> name
Nothing -> "Anonymous"...
Maybe Type
-- norun
enum Maybe a = Just(a) | NothingMultiple Head
let list = [1, 2, 3, 4]
case list of
a :: b :: rest -> a + b
x :: xs -> x
[] -> 0Nested Match
let data = (3, 4)
case data of
(a, b) -> a + bOr Patterns
enum Day
= Monday
| Tuesday
| Wednesday
| Thursday
| Friday...
Qualified Enum
enum Color = Red | Green | Blue
let color = Color::Green
case color of
Color::Red -> "fire"...
Recursive Sum
fn sum : [Int] -> Int
fn sum list =
case list of
[] -> 0
x :: xs -> x + sum xs
...
Result Handling
import String
let parseResult = Ok 42
case parseResult of
Ok n -> "Parsed: " ++ String.fromInt n...
Result Type
-- norun
enum Result a e = Ok(a) | Err(e)Data Contracts
Display Mapped
import DataFrame
enum Country
= Germany
| BurkinaFaso "Burkina Faso"
| UnitedKingdom "United Kingdom"...
Geographic
import DataFrame
enum Region
= NorthEast "North East"
| NorthWest "North West"
| Midlands...
Inline Value Labels
import DataFrame
enum Education = Primary | Secondary | Tertiary | Postgraduate
let survey : DataFrame {
respondent_id: Int,...
Multiple Columns
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
import DataFrame
enum YesNo = No | Yes
let data : DataFrame {
response: [(0, YesNo::No), (1, YesNo::Yes), ..]...
Open Closed Schema
import DataFrame
enum Status = Active | Inactive | Pending
let exact : DataFrame { id: Int, name: String, status: Status } = DataFrame.readCsv "users.csv"
...
Stata Value Labels
-- norun
import DataFrame
enum Employment
= Employed (ValueLabel 1 "Employed")...
String Enum
import DataFrame
enum City = Berlin | Munich | Hamburg
let data : DataFrame { name: String, city: City, .. } = DataFrame.readCsv "users.csv"Survey Use Case
import DataFrame
enum AgeGroup
= Under18 "Under 18"
| Young "18-34"
| Middle "35-54"...
Value Label Shorthand
-- norun
import DataFrame
enum Education
= Primary (ValueLabel 1 "Primary")...
Value Label Type
import DataFrame
import ValueLabelSet
enum Education
= Primary (ValueLabel 1 "Primary")
| Secondary (ValueLabel 2 "Secondary")...
Dataframe
Dataframe Corr
import DataFrame
-- Pearson correlation matrix
let data =
DataFrame.fromRecords
[ { x = 1, y = 2 }...
Dataframe Corr Spearman
import DataFrame
-- Spearman rank correlation matrix (robust to outliers and non-linear monotone relationships)
let data =
DataFrame.fromRecords
[ { x = 1, y = 2 }...
Dataframe Quantiles
import DataFrame
-- Multiple quantiles in one call
let data =
DataFrame.fromRecords
[ { score = 78 }...
Dataframe Statistics
import DataFrame
-- Column-wise descriptive statistics
let data =
DataFrame.fromRecords
[ { score = 78 }...
Expr Aggregation
-- Aggregation with DataFrame.Expr
import DataFrame
import DataFrame.Expr as Expr
DataFrame.fromRecords...
Expr Arithmetic
-- Pipe-style arithmetic: Expr.mul for column * column
import DataFrame
import DataFrame.Expr exposing col
import Result
import DataFrame.Expr as Expr...
Expr Basics
-- DataFrame.Expr for composable column operations
import DataFrame
import DataFrame.Expr exposing col
import Result
import DataFrame.Expr as Expr...
Expr Captured Var
-- Outer-scope variables are captured in expressions
import DataFrame
import Result
import DataFrame.Expr as Expr
...
Expr Case
-- Multi-branch conditional with Expr.cond
import DataFrame
import Result
import DataFrame.Expr as Expr
...
Expr Comparison
-- Pipe-style comparison: Expr.gte for column >= literal
import DataFrame
import DataFrame.Expr exposing col
import Result
import DataFrame.Expr as Expr...
Expr Concat
import DataFrame
import Result
import DataFrame.Expr as Expr
let full = Expr.concatMany " " [@first, @last]...
Expr Conditional
-- Conditional expressions with DataFrame.Expr
import DataFrame
import DataFrame.Expr exposing col, lit
import Result
import DataFrame.Expr as Expr...
Expr Cumsum Extra
import DataFrame
-- Running sum per region using window functions
DataFrame.fromRecords
[ { region = "East", revenue = 100 }
, { region = "East", revenue = 200 }...
Expr Cumulative
import DataFrame
-- Cumulative sum and mean per region using window functions
DataFrame.fromRecords
[ { region = "East", revenue = 100 }
, { region = "East", revenue = 200 }...
Expr Date
import DataFrame
import DataFrame.Expr exposing col, lit
import Result
import DataFrame.Expr as Expr
...
Expr Datetime
import DataFrame
import DataFrame.Expr exposing col
import Result
import DataFrame.Expr as Expr
...
Expr Float Pred
import DataFrame
import DataFrame.Expr exposing col
import Result
import DataFrame.Expr as Expr
...
Expr If Else
-- Simple if/else conditional with Expr.cond
import DataFrame
import Result
import DataFrame.Expr as Expr
...
Expr Import
import DataFrame
import Result
import DataFrame.Expr as Expr
let source =...
Expr In
-- 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
-- Infix arithmetic operators work directly on column references
import DataFrame
import Result
import DataFrame.Expr as Expr
...
Expr Infix Boolean
-- Boolean logic: && and || work with Expr values
import DataFrame
import Result
let df =
DataFrame.fromRecords...
Expr Infix Chained
-- Chained infix operations respect operator precedence
import DataFrame
import Result
import DataFrame.Expr as Expr
...
Expr Infix Comparison
-- Infix comparison operators produce boolean Expr for filtering
import DataFrame
import Result
let df =
DataFrame.fromRecords...
Expr Infix Scalar
-- Scalars are auto-coerced to Expr when used with infix operators
import DataFrame
import Result
import DataFrame.Expr as Expr
...
Expr Math
-- Math functions: abs
import DataFrame
import Result
import DataFrame.Expr as Expr
...
Expr Mutate
-- Add a computed column with applyExprs using tuple syntax
import DataFrame
import Result
import DataFrame.Expr as Expr
...
Expr Null
-- Null handling: fillNull
import DataFrame
import DataFrame.Expr exposing col
import Result
import DataFrame.Expr as Expr...
Expr Operators Overview
-- Operators work directly on column references
import DataFrame
import Result
import DataFrame.Expr as Expr
...
Expr Quantile
import DataFrame
import DataFrame.Expr as Expr
-- Interquartile range components
let q1 =...
Expr Regex String
-- Extract year from date strings using regex capture
import DataFrame
import Result
import DataFrame.Expr as Expr
...
Expr Reuse
import DataFrame
import Result
import DataFrame.Expr as Expr
let revenue = @price * @qty...
Expr Rolling
import DataFrame
-- Rolling window operations using partitionBy + withRollingSum/withRollingMean
DataFrame.fromRecords
[ { region = "East", value = 1 }
, { region = "East", value = 2 }...
Expr Rolling Extra
import DataFrame
-- 7-day rolling average using window functions
DataFrame.fromRecords
[ { dept = "East", sales = 10 }
, { dept = "East", sales = 20 }...
Expr Split
import DataFrame
import DataFrame.Expr exposing col
import Result
import DataFrame.Expr as Expr
...
Expr String Extra
import DataFrame
import Result
import DataFrame.Expr as Expr
-- Whitespace trimming (both sides)...
Expr String Ops
-- String operations with DataFrame.Expr
import DataFrame
import Result
import DataFrame.Expr as Expr
...
Expr String Transform
-- String transformation chain
import DataFrame
import DataFrame.Expr exposing col
import Result
import DataFrame.Expr as Expr...
Expr Symbol Col
-- @name column references work directly with infix operators
import DataFrame
import Result
import DataFrame.Expr as Expr
...
Expr Type Cast
import DataFrame
import DataFrame.Expr exposing col
import Result
import DataFrame.Expr as Expr
...
Expr Window
import DataFrame
import Result
import DataFrame.Expr as Expr
let df =...
Lineage Agg Origin
import DataFrame
import DataFrame.Expr exposing col
import List
import DataFrame.Expr as Expr
...
Lineage Auto
-- norun
-- Lineage appears automatically when printing a DataFrame
import DataFrame
import DataFrame.Expr as Expr
import Result
...
Lineage Byid
-- lineageById looks up a DataFrame in the lineage registry by its UUID
import DataFrame
import Maybe
let df =
DataFrame.fromRecords...
Lineage Byname
-- 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
-- norun
-- DataFrame.columnLineage returns origin info for a column
import DataFrame
let df = DataFrame.fromRecords [{ name = "Alice", age = 30 }]
...
Lineage Dag Join
-- Join produces two parents in the DAG
import DataFrame
import List
let users =
DataFrame.fromRecords...
Lineage Full Record
-- norun
-- Full lineage record structure
import DataFrame
import DataFrame.Expr as Expr
import Result
...
Lineage Global Ops
-- norun
-- Global operations (filter, sort) are tracked separately
import DataFrame
let df =
DataFrame.fromRecords...
Lineage Join Origin
-- norun
-- Joined columns track their source DataFrame
import DataFrame
let users =
DataFrame.fromRecords...
Lineage Parents Derived
-- Derived DataFrames track parent operations
import DataFrame
import List
import Result
let df =...
Lineage Parents Root
-- Root DataFrames have no parents
import DataFrame
let df = DataFrame.fromRecords [{ name = "Alice", age = 30 }]
DataFrame.parents dfLineage Rename Origin
-- norun
-- After rename, the transformation tracks the operation
import DataFrame
import Result
let df = DataFrame.fromRecords [{ name = "Alice", age = 30 }]...
Lineage Sourcepath
-- DataFrame.sourcePath returns Nothing for fromRecords
import DataFrame
let df =
DataFrame.fromRecords
[ { name = "Alice", age = 30 }...
Lineage Tracking
-- Track data transformation history
import DataFrame
import DataFrame.Expr as Expr
import Result
-- Create data and track transformations...
Lineage Transformations
-- norun
-- Columns track their transformation history
import DataFrame
import Result
let df =...
Melt Reshape
-- 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
-- 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
-- Remap values with automatic label transfer
import DataFrame
let df =
DataFrame.fromRecords
[ { id = 1, score = 1 }...
Value Labels
-- Attach value labels for coded variables
import DataFrame
import ValueLabelSet
let gender = ValueLabelSet.fromList [(1, "Male"), (2, "Female")]
...
Variable Labels
-- Variable labels for column descriptions
import DataFrame
let df =
DataFrame.fromRecords
[ { id = 1, gender = 1 }...
Window Functions
-- SQL-style window functions
import DataFrame
-- Sample sales data with rank column
DataFrame.fromRecords
[ { product = "Laptop", revenue = 1200, rank = 1 }...
Withcolumns Batching
-- applyExprs batches exprs so later ones can reference columns added earlier
import DataFrame
import Result
import DataFrame.Expr as Expr
...
Dataframe Type Safety
Compile Time Paths
import DataFrame
let path = "data.csv"
let dir = "data/"
let a : DataFrame { name: String, .. } =...
Schema Annotation
import DataFrame
let data : DataFrame { name: String, age: Int, city: String } =
case DataFrame.readCsv "users.csv" of
Ok df -> df
Err _ -> DataFrame.fromRecords []Type Alias Row Schema
import DataFrame
type alias Row = { x : Int, y : String }
let rows : [Row] =
[ { x = 1, y = "a" }...
Date
Arithmetic
-- Date arithmetic
import Date
let date =
case Date.fromYmd 2024 3 15 of
Ok d -> d...
Comparison
-- Comparing dates and computing differences
import Date
let start =
case Date.fromYmd 2024 1 1 of
Ok d -> d...
Components
-- Extracting date components
import Date
let date =
case Date.fromYmd 2024 3 15 of
Ok d -> d...
Create
-- Creating dates from year, month, day
import Date
Date.fromYmd 2024 3 15Error Handling
import Date
-- Invalid date returns a typed error
case Date.fromYmd 2024 2 30 of
Ok date -> Date.toIsoString date
Err _ -> "Invalid day for this month"Parse
-- Parsing dates from strings
import Date
Date.parseIso "2024-06-15"Parse Custom
import Date
-- Custom format
Date.parse "15/06/2024" "%d/%m/%Y"Datetime
Interop Combine
import Date
-- Combine Date and Time into DateTime
import DateTime
import Time
let date =...
Interop Fromdate
import Date
-- Convert Date to DateTime at midnight UTC
import DateTime
let date =
case Date.fromYmd 2024 1 1 of...
Interop Getdate
import Date
-- Extract Date component from DateTime
import DateTime
let dt =
case DateTime.fromYmd 2024 6 15 of...
Interop Gettime
-- Extract Time component from DateTime
import DateTime
import Time
let dt =
case DateTime.fromParts 2024 6 15 14 30 0 of...
Decimal
Comparison
-- Decimal comparison and checks
import Decimal
let a = 10.5d
let b = 3.2d...
Conversion
-- Converting between Decimal and other types
import Decimal
let price = 19.99d
-- Convert to string...
Literals
-- Decimal literals use the 'd' suffix
import Decimal
let price = 19.99d
let taxRate = 0.073d...
Parsing
-- Parse a string into a Decimal
import Decimal
Decimal.parse "42.5"Rounding
-- Rounding decimals to specific precision
import Decimal
let price = 19.99d
let taxRate = 0.073d...
Duration
Arithmetic
-- Duration arithmetic
import Duration
let oneHour = Duration.fromHours 1
let thirtyMin = Duration.fromMinutes 30...
Comparison
-- Duration comparison and checks
import Duration
let d = Duration.fromMinutes 90
Duration.isPositive dConversion
-- Converting between duration units
import Duration
let d = Duration.fromMinutes 150
-- Get total hours (truncated)...
Create
-- Creating and converting durations
import Duration
let twoHours = Duration.fromHours 2
Duration.toSeconds twoHoursError Handling
Arg Type Map
import List
List.map 42 [1, 2, 3]
-- Error: Type mismatch: expected (a -> b), found Int
...
Arg Type String
import String
String.length 42
-- Error: Type mismatch: expected String, found Int
...
Block Align
if True then
0
else -- Error: 'else' must align with 'if'
1Block Missing Indent
fn greet : String -> String
fn greet name =
"Hello, " ++ name -- Error: body must be indented by at least 4 spacesBlock Nest
let x =
x + 1 -- Error: Block must be indented more than parent
-- Hint: Indent the block to 4 spacesBool Correct
let x = True
let y = False
x && yBool Error
let x = true -- Error: 'true' is not a Keel keyword
-- Hint: Use `True` for boolean trueBounds Error
let items = [1, 2, 3]
items[10] -- Error: Index 10 out of bounds for list of size 3Bounds Safe
let items = [1, 2, 3]
items[0] -- 1Branch Correct
let x = 2
case x of
1 -> "one"
2 -> "two"
_ -> "other"Branch Mismatch
let x = 2
case x of
1 -> 42 -- Int
2 -> "hello" -- Error: Case branches have incompatible types: Int and String
_ -> 0Constructor Type
case Just 5 of
Ok n -> n -- Error: Pattern type mismatch: expected Maybe, but pattern is Result (Ok)
_ -> 0Converting Types
import Result
-- Maybe to Result (with error message)
let a = Just 5 |> Result.fromMaybe "was nothing"
-- Result to Maybe (discards error)...
Correct Syntax
fn double : Int -> Int
fn double x =
x * 2
-- Pattern matching uses case...of
...
Else Align
let x = 10
let result =
if x > 5 then "big"
else "small" -- Error: else must align with ifEnum Case
enum Direction = North | south -- Error: Enum variant must start with uppercaseFn Missing Sig
fn double x = -- Error: missing type signature
x * 2Fuzzy Multiple
import IO exposing print
let userName = "Alice"
let userAge = 30
...
Fuzzy Single
import IO exposing print
let userName = "Alice"
let userAge = 30
...
Generic Annotation
import Json
let data = Json.parse "{\"x\": 1}"
-- Error: Generic function result requires a type annotation for variable 'data'
...
Guard Correct
let x = 5
case x of
n if n > 0 -> "positive"
n if n < 0 -> "negative"
_ -> "zero"Guard Type
let x = 2
case x of
n if n + 1 -> "bad" -- Error: Guard expression must be Bool, found Int
_ -> "ok"Indent Error
fn example : Int -> Int
fn example x =
let y = 1 -- Error: Function body must be indented by at least 4 spaces
x + yJs Record
{ 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
import Json
let data : Result { x : Int } String = Json.parse "{\"x\": 1}"
dataKeywords
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 bindingsMaybe Correct
let present = Just 42
let absent = Nothing
case present of
Just n -> "Got a value"...
Maybe Module
import Maybe
-- Transform present values
let mapped = Just 5 |> Maybe.map (|x| x * 2)
-- Chain operations that might return Nothing...
Mismatched Delim
let x = [1, 2)
-- Error: Mismatched delimiter — '(' expected ')' but found ')'Module Fn Typo
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
let x = null -- Error: 'null' is not a Keel keyword
-- Hint: Use `Nothing` for absent valuesPattern Type
case 42 of
"hello" -> 1 -- Error: Pattern type mismatch: expected Int, but pattern is String
_ -> 0Record Correct
{ name = "Alice", age = 30 }Result Module
import Result
-- Transform success values
let mapped : Result Int String = Ok 5 |> Result.map (|x| x * 2)
-- Chain operations that might fail...
Scope
fn example : Int -> Int
fn example x =
let inner = x + 1
inner
inner -- Error: Variable 'inner' is not in scopeTry Operator
-- Unwrap Ok with ?, short-circuit on Err
let addOne = |x: Int| Ok (x + 1)
let result = 5 |> addOne
result?Try Operator Err
-- 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
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
fn add : Int -> Int -> Int
fn add x y =
x + y
add "hello" 5 -- Error: Expected Int but got StringType Vs Alias
enum Person = { name: String, age: Int }
-- Error: Expected enum variant, found record syntax
-- Hint: Use an inline record type annotation instead.Unclosed Paren
let x = (1 + 2
-- Error: Unclosed '(' — expected ')'Undeclared
let x = unknownVar -- Error: Variable 'unknownVar' is not declaredUnexpected Delim
let x = 1 + 2]
-- Error: Unexpected ']' — no matching '['Variant Parens
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
module CustomMath exposing ..
fn add : Int -> Int
fn add x =
x + 1
...
Arity Overloading 2
module CustomMath exposing ..
fn add : Int -> Int
fn add x =
x + 1
...
Common Filter
import List
-- filter: keep matching elements
[1, 2, 3, 4] |> List.filter (|x| x > 2)Common Fold
import List
-- fold: reduce to single value
[1, 2, 3, 4] |> List.foldl (|acc x| acc + x) 0Common Map
import List
-- map: transform each element
[1, 2, 3] |> List.map (|x| x * 2)Composition
fn double : Int -> Int
fn double x =
x * 2
fn addOne : Int -> Int
fn addOne x =...
Currying
fn add : Int -> Int -> Int
fn add x y =
x + y
let add5 = add 5
...
Defining
fn greet : String -> String
fn greet name =
"Hello, " ++ name ++ "!"
greet "Alice" -- "Hello, Alice!"Duplicate Sig
fn add : Int -> Int
fn add x = x + 1
fn add : Int -> Int
fn add x = x + 2Factorial
module CustomMath exposing factorial
fn factorial : Int -> Int
fn factorial n =
if n <= 1 then
1...
Factorial Case
fn factorial : Int -> Int
fn factorial n =
case n of
0 -> 1
1 -> 1
_ -> n * factorial (n - 1)...
Fibonacci
module CustomMath exposing fibonacci
fn fibonacci : Int -> Int
fn fibonacci n =
if n <= 1 then
n...
Generic Assign
import List
let doubled = List.map (|x| x * 2) [1, 2, 3]
let result =
[1, 2, 3, 4, 5]...
Generic Compose
fn compose : (b -> c) -> (a -> b) -> a -> c
fn compose g f x =
g (f x)
let double = |x : Int| x * 2
...
Generic Identity
fn identity : a -> a
fn identity x =
x
identity 42Higher Order
-- Takes a function as argument
fn applyTwice : (Int -> Int) -> Int -> Int
fn applyTwice f x =
f (f x)
applyTwice (|x : Int| x + 1) 5 -- 7Higher Order Context
module M exposing ..
fn apply : (Int -> Int) -> Int -> Int
fn apply f x =
f x
...
Lambda As Pattern
let withAlias = |x : Int as m| (x, m)
withAlias 42Lambda Basics
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
-- 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 1Lambda Map
import List
[1, 2, 3] |> List.map (|x| x * 2)Lambda Multiline
let compute =
|x : Int|
let y = 3
x + y
compute 7Lambda No Annotation
|x| xLambda Record Fields
let describe = |{ name: String, age: Int }| name
describe { name = "Alice", age = 30 }Lambda Rest Pattern
let getName = |{ name: String, .. }| name
getName { name = "Alice", age = 30 }Lambda Tuple Add
let addPair = |(x : Int, y : Int)| x + y
addPair (3, 4)Lambda Typed
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
let f = |x : Int| x + 1
f 1Local Bindings
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
fn makeAdder : Int -> (Int -> Int)
fn makeAdder n =
|x : Int| x + n
makeAdder 10 5Native Pipes
import List
import Math
import String
let a =
"hello"...
Overloaded Hof
module Apply exposing ..
fn apply : (Int -> Int) -> Int -> Int
fn apply f x =
f x
...
Overloading Int
module CustomMath exposing ..
fn double : Int -> Int
fn double x =
x * 2
...
Overloading String
module CustomMath exposing ..
fn double : Int -> Int
fn double x =
x * 2
...
Overloading Toplevel
fn inc : Int -> Int
fn inc x =
x + 1
fn inc : Float -> Float
fn inc x =...
Pattern Matching Fn
fn length : [a] -> Int
fn length list =
case list of
[] -> 0
x :: xs -> 1 + length xs
...
Pipe Chain
fn double : Int -> Int
fn double x =
x * 2
fn addOne : Int -> Int
fn addOne x =...
Pipe Operator
-- Pipe operator provides context from the left operand
5 |> |x| x + 1Pipeline Example
import List
[1, 2, 3, 4, 5]
|> List.filter (|x| x > 2)
|> List.map (|x| x * 2)Record Field Pipe
-- Mixed typed and untyped fields (untyped inferred from context)
{ x = 1, y = 2 } |> |{ x: Int, y }| x + yStdlib Chained Inference
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
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
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
import List
-- Lambda parameter type inferred from List.map signature
List.map (|x| x * 2) [1, 2, 3]
-- [2, 4, 6]Stdlib Zipwith Inference
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
fn fst : (Int, String) -> Int
fn fst pair =
case pair of
(x, _) -> x
fst (42, "hello")Tuple Arg Swap
fn swap : (a, b) -> (b, a)
fn swap pair =
case pair of
(x, y) -> (y, x)
swap (1, "hello")Type Signatures
fn add : Int -> Int -> Int
fn add x y =
x + y
add 3 4 -- 7Getting Started
Http
Indentation
Basic Blocks
-- Function body must be indented
fn addOne : Int -> Int
fn addOne x =
x + 1
addOne 5 -- 6Case Indentation
-- Case branches must be indented from 'case'
let value = 2
let result =
case value of
1 -> "one"...
Case Multiline Body
-- Case branch bodies can span multiple lines
let value = 2
let result =
case value of
1 ->...
Continuation Argument
-- Multiline arguments work with COLLECTIONS (lists, records, tuples)
-- NOT with simple values like integers
import List
...
If Multiline
-- If-then-else with multiline expressions
let condition = True
let result =
if condition then
1 + 2...
Let Block
-- 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
-- Lists can span multiple lines (Elm-style)
import List
let numbers = [1, 2, 3, 4, 5]
List.sum numbers...
Local Fn Args
fn add : Int -> Int -> Int
fn add x y =
x + y
let result = add 1 2
...
Multiline Function Call
-- 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
import List
List.map (|x| x * 2) [1, 2, 3]Pipe Multiline
-- Pipes work naturally with multiline formatting
import List
let result =
[1, 2, 3, 4, 5]
|> List.map (|x| x * 2)...
Record Multiline
-- Records can span multiple lines (Elm-style)
let person =
{ name = "Alice"
, age = 30
, city = "Paris"
}...
Scope Nested
-- 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
fn example : Int -> Int
fn example n =
let a = n + 1
let b = a * 2
let c = a + b
c...
Separate Expressions
-- Lines at the SAME indentation are separate expressions
let x = 1
let y = 2
let z = 3...
Landing
Compile Time Safety
-- Type-safe column operations validated at compile time
import DataFrame
import DataFrame.Expr exposing col
import DataFrame.Expr as Expr
import Result
...
Compliance
-- Built-in audit trails for regulatory compliance
import DataFrame
import Result
let payments =
case DataFrame.readParquet "public/data/payments.parquet" of...
Data Contracts
-- Data contracts: schema enforced by the compiler, not documentation
import DataFrame
-- Read and validate DataFrame schema at compile time
let customers =
case DataFrame.readParquet "public/data/customers.parquet" of...
Data Lineage
-- Automatic data lineage tracking
import DataFrame
import DataFrame.Expr exposing col
import DataFrame.Expr as Expr
import Result
...
Lexical
Bool Literals
TrueChar Literals
'a'Decimal Literals
42d -- Integer decimal
3.14d -- Fractional decimalFloat Literals
3.14Indentation
fn example : Int -> Int
fn example x =
let y = 1 -- Must be indented
x + y
example 1Int Literals
42 -- DecimalLine Comments
-- This is a line comment
let x = 42 -- Inline comment
xRecord Syntax
{ name = "Alice", age = 30 }String Literals
"Hello, World!"Unit Literal
()Matrix
Arithmetic
-- Matrix multiplication and element-wise operators
import Matrix
let a = Matrix.fromRows [[1.0, 2.0], [3.0, 4.0]]
let b = Matrix.fromRows [[5.0, 6.0], [7.0, 8.0]]
...
Basics
-- Matrix basics: creation, shape, and element access
import Matrix
let m = Matrix.fromRows [[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]
Matrix.shape mInt Matrix
-- Integer matrices for exact arithmetic
import Matrix
let m = Matrix.fromRowsInt [[1, 2], [3, 4]]
Matrix.toRows mLinear System
-- Solve a linear system Ax = b using LU decomposition
import Matrix
-- Solve: 2x = 6, 4y = 8
let a = Matrix.fromRows [[2.0, 0.0], [0.0, 4.0]]
let b = Matrix.fromList [6.0, 8.0]...
Svd
-- SVD decomposition: singular values of a 2x2 matrix
import Matrix
import List
let m = Matrix.fromRows [[4.0, 3.0], [6.0, 3.0]]
let (u, s, vt) = Matrix.svd m...
Modules
Access Add
module CustomMath exposing add, multiply
fn add : Int -> Int -> Int
fn add x y =
x + y
...
Access Multiply
module CustomMath exposing multiply
fn multiply : Int -> Int -> Int
fn multiply x y =
x * y
...
Exposing
-- norun
-- Expose specific items
module exposing functionA, functionB, TypeA
-- Expose all
module exposing .....
Fibonacci
module CustomMath exposing fibonacci
fn fibonacci : Int -> Int
fn fibonacci n =
if n <= 1 then
n...
File Level
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
import Math
module Geometry exposing Shape, area, perimeter
enum Shape
= Circle(Float)...
Geometry Perimeter
module Geometry exposing perimeter
fn perimeter : Float -> Float
fn perimeter r =
2.0 * 3.14159 * r
...
Import Alias Exposing
import List as L exposing length
length [1, 2]Import Aliases
import List as L
-- Modules and import aliases
import Math as M
M.abs (L.length [1, 2, 3])Import Exposing
import List exposing map
-- Using built-in list functions directly
[1, 2, 3] |> map (|x| x * 2) -- [2, 4, 6]Import Exposing Bare
import List exposing map, filter
map (|x : Int| x + 1) [1, 2, 3]Indent Correct
module CustomMath exposing add
fn add : Int -> Int -> Int
fn add x y =
x + y
...
Indent Error
-- Error: Inline module content must be indented
module CustomMath exposing add
fn add x y = x + y -- Wrong: not indentedInline
module CustomMath exposing add, multiply
fn add : Int -> Int -> Int
fn add x y =
x + y
...
Math Module
-- norun
module exposing double, square
fn double : Int -> Int
fn double x = x * 2...
Recursive
module CustomMath exposing factorial, fibonacci
fn factorial : Int -> Int
fn factorial n =
if n <= 1 then
1...
Shadowing Math
module Math exposing double
fn double : Int -> Int
fn double x =
x * 2
...
Shapes Enum Module
module Shapes exposing Shape, area
enum Shape
= Circle(Float)
| Square(Float)
...
Stdlib Qualified
import Json
import List
import Maybe
import Result
import String
...
Uses Stdlib
-- norun
module exposing greeting
import String
...
Operators
Arithmetic
let addition = 5 + 3
let subtraction = 10 - 4
let multiply = 6 * 7
...
Comparison
let eq = 5 == 5
let neq = 5 != 6
let lt = 3 < 5
...
Compose Backward
-- Backward composition (g first, then f)
let addOne = |x : Int| x + 1
let double = |x : Int| x * 2
let doubleThenAdd = addOne << double...
Compose Forward
-- Forward composition (f first, then g)
let addOne = |x : Int| x + 1
let double = |x : Int| x * 2
let addThenDouble = addOne >> double...
Division
let floatDiv = 10 / 3
let intDiv = 10 // 3
(floatDiv, intDiv)List Ops
-- Cons (prepend element)
let consed1 = 1 :: [2, 3]
let consed2 : [Int] = 1 :: (2 :: [])
-- Concatenation...
Logical
-- And (both must be True)
let and1 = True && True
let and2 = True && False
-- Or (at least one must be True)...
Pipe Forward
fn double : Int -> Int
fn double x =
x * 2
fn addOne : Int -> Int
fn addOne x =...
Pipeline
import List
-- Pipeline example
[1, 2, 3, 4, 5]
|> List.filter (|x| x > 2)
|> List.map (|x| x * 2)...
Short Circuit
-- False && ... returns False immediately without evaluating the right side
let result = False && True
result -- FalseString Concat
"Hello, " ++ "World!"Try Operator
-- ? unwraps Ok values and short-circuits on Err
let addOne = |x: Int| Ok (x + 1)
let result = 5 |> addOne
result?Type Promotion
let x = 1 + 2.5
let y = 3 * 1.5
x + yPattern Matching
As Pattern
let maybe = Just 42
case maybe of
Just x -> (x, Just x)
Nothing -> (0, Nothing)As Pattern List
let list = [1, 2, 3]
case list of
x :: xs as all -> "Head"
[] -> "empty"Branch Mismatch
case 1 of
1 -> 42 -- Int
2 -> "hello" -- Error: Case branches have incompatible types
_ -> 0Cons
let list = [1, 2, 3]
case list of
x :: xs -> x -- x is the head, xs is the tail
[] -> 0 -- empty list caseConstructor
let maybeValue = Just 42
case maybeValue of
Just x -> "Got value"
Nothing -> "Nothing"Exhaustive
enum TrafficLight = Red | Yellow | Green
let light = TrafficLight::Yellow
case light of
TrafficLight::Red -> "stop"...
Fn Nested
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
fn fst : (a, b) -> a
fn fst pair =
case pair of
(x, _) -> x
fst...
Guard Exhaustive
let x = 0
case x of
n if n > 0 -> "positive"
n if n < 0 -> "negative"
_ -> "zero"Guards
let number = 42
case number of
n if n < 0 -> "negative"
n if n == 0 -> "zero"
n if n < 10 -> "small positive"...
Lambda Record
-- Record destructuring
let describe = |{ name: String, age: Int }| name
describe { name = "Bob", age = 25 }Lambda Tuple
-- Tuple destructuring
let addPair = |(x : Int, y : Int)| x + y
addPair (3, 4) -- 7Let Record
let user = { name = "Alice", age = 30 }
let { name, age } = user
nameLet Tuple
let point = (10, 20)
let (x, y) = point
x + yList Exact
let list = [1, 2]
case list of
[] -> "empty"
[x] -> "single"
[x, y] -> "pair"...
Literal
let x = 1
case x of
0 -> "zero"
1 -> "one"
_ -> "many"Multi Cons
let list = [1, 2, 3, 4]
case list of
a :: b :: rest -> a + b
x :: xs -> x
[] -> 0Nested
import String
let result = Ok Just 5
case result of
Ok (Just x) -> "Success with value: " ++ String.fromInt x...
Or Binding
let point = (5, 2)
case point of
(x, 1) | (x, 2) | (x, 3) -> x -- x is bound in all alternatives
_ -> 0Or Pattern
enum Direction
= North
| South
| East
| West
...
Qualified Enum
enum Color = Red | Green | Blue
let color = Color::Green
case color of
Color::Red -> "fire"...
Record
let person = { name = "Alice", age = 30 }
case person of
{ name, age } -> nameRecord Rest
let user =
{ name = "Bob"
, age = 25
, email = "bob@example.com"
}
...
Recursive
fn sum : [Int] -> Int
fn sum numbers =
case numbers of
[] -> 0
x :: xs -> x + sum xs
...
Tuple
let pair = (3, 0)
case pair of
(0, 0) -> "origin"
(x, 0) -> "on x-axis"
(0, y) -> "on y-axis"...
Type Mismatch
case 42 of
"hello" -> 1 -- Error: Pattern type mismatch: expected Int, but pattern is String
_ -> 0Type Unify
let x = 2
case x of
1 -> 42 -- Int
2 -> 3.14 -- Float: compatible, unifies to Float
_ -> 0Unreachable
let x = False
case x of
_ -> "anything" -- This matches everything
True -> "true" -- Warning: Unreachable patternVariable
let point = (3, 4)
case point of
(x, y) -> x + yVariant Patterns
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
let tuple = (42, "ignored")
case tuple of
(x, _) -> x -- Ignore second elementProcess
Runtime Errors
Div Safe
import String
fn safeDivide : Int -> Int -> String
fn safeDivide a b =
if b == 0 then
"Cannot divide by zero"...
Div Zero
let divisor = 0
10 / divisorList Bounds
let items = [1, 2, 3]
items[10]List Safe
import List
let items = [10, 20, 30]
-- Safe access returns Maybe
case List.nth 1 items of...
Tuple Bounds
let triple = (1, 2, 3)
triple.5Table
Builder
-- Builder pattern for custom tables
import DataFrame
import Table
DataFrame.fromRecords
[ { region = "North", sales = 100 }...
Cross
-- Two-way cross-tabulation
import DataFrame
import Table
DataFrame.fromRecords
[ { gender = "M", group = "A" }...
Freq
-- One-way frequency table
import DataFrame
import Table
DataFrame.fromRecords
[ { category = "A" }...
Summary Stats
-- Summary statistics by group
import DataFrame
import Table
DataFrame.fromRecords
[ { region = "North", sales = 100 }...
Time
Arithmetic
-- Time arithmetic
import Time
let t =
case Time.fromHms 14 30 0 of
Ok t -> t...
Components
-- Extracting time components
import Time
let t =
case Time.fromHms 14 30 0 of
Ok t -> t...
Create
-- Creating time values
import Time
Time.fromHms 14 30 0Parse
-- Parsing time from strings
import Time
Time.parseIso "09:15:30"Types
03b Record Newtype
type Person = { name: String, age: Int }
let p = Person { name = "Alice", age = 30 }
case p of
Person { name } -> name03c Tuple Newtype
type Pair = (Int, String)
let p = Pair (1, "x")
case p of
Pair (n, _) -> nAlias Resolved
-- norun
-- UserId and PostId are distinct types — not interchangeable
type UserId = Int
type PostId = Int
fn greet : UserId -> String...
Bool Int Error
True + 1Bracket List All
let numbers : [Int] = [1, 2, 3]
let names : [String] = ["Alice", "Bob"]
let nested : [[Int]] = [[1, 2], [3, 4]]
...
Case Pattern
-- Case expression patterns
case (42, "test") of
(x, y) -> yCompound
-- List of integers
let numbers =
[1, 2, 3]
-- Tuple
let pair = (42, "answer")...
Decimal Type
let price = 19.99d
let tax = 0.07d
let total = price + price * tax
...
Generic Pair
enum Pair a b = Pair(a, b)
let p = Pair::Pair (1, "hello")
pGeneric Tree
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
-- Higher-order function context
import List
-- Higher-order function context
[1, 2, 3] |> List.map (|x| x * 2)
...
Inference
let x = 42 -- Inferred as Int
let name = "Alice" -- Inferred as String
let ratio = 3.14 -- Inferred as Float
...
Inference Annotation
import List
let empty : [Int] = [] -- Needed: can't infer element type
List.length emptyJson Parse Annotation
import Json
let data : Result { name : String } String = Json.parse "{\"name\": \"Alice\"}"
dataLambda Annotation
(|x : Int| x + 1) 1Lambda Pattern
-- Lambda parameter patterns with context
(1, 2) |> |(a, b)| a + bMaybe Type
-- norun
enum Maybe a = Just(a) | NothingMaybe Usage
let present = Just 42
let absent = Nothing
case present of
Just n -> "Got a value"...
Multiline Enum
enum Direction
= North
| South
| East
| West
...
Numeric Promotion
let x = 1 + 2.5
let y = 3 * 1.5
x + yOpen Record Alias
let p : { name : String, age : Int, .. } =
{ name = "Alice"
, age = 30
, email = "a@b.com"
}
...
Open Record Dataframe
import DataFrame
-- Open record type allows extra fields
let data : DataFrame { name : String, age : Int, .. } =
DataFrame.fromRecords...
Parameterized Alias
type Validated a = a
let score : Validated Int = Validated 99
case score of
Validated n -> nParenthesized All
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
-- Pipe operator provides context
5 |> |x| x + 1Primitives
let x = 42
let pi = 3.14
let active = True
...
Record Type
let user : { id : Int, name : String, email : String, active : Bool } =
{ id = 1
, name = "Alice"
, email = "alice@example.com"
, active = True
}...
Recursive
enum MyList a = Nil | Cons(a, MyList a)
let nums =
MyList::Cons (1, MyList::Cons (2, MyList::Cons (3, MyList::Nil)))
numsResult Err
let failure = Err "something went wrong"
case failure of
Ok value -> "Success"
Err msg -> "Error: " ++ msgResult Ok
let success = Ok 42
case success of
Ok value -> "Success"
Err msg -> "Error: " ++ msgResult Type
-- norun
enum Result a e = Ok(a) | Err(e)Shape Construction
enum Shape
= Circle(Float)
| Rectangle(Float, Float)
Shape::Rectangle (10.0, 20.0)Simple Enum
enum Direction
= North
| South
| East
| West
...
Symbol Basic
[:north, :south, :east]Symbol Equality
[:north == :north, :north == :south]Symbol Field Names
-- 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
let dir = :north
case dir of
:north -> "going up"
:south -> "going down"
_ -> "going sideways"Symbol Quoted
:"hello world"Tuple Destructure
-- Tuple destructuring
let pair = (1, "hello")
let (x, y) = pair -- x: Int, y: String
yType Alias
type UserId = Int
let id = UserId 42
case id of
UserId n -> nType Alias All
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 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 alias Box a = { value : a }
let b : Box Int = { value = 42 }
b.valueType Alias Record
type alias Person = { name : String, age : Int }
let p : Person = { name = "Alice", age = 30 }
p.ageType Alias Scalar
type alias UserId = Int
let id : UserId = 42
id + 1Type Alias Vs Newtype
-- type alias: transparent — a plain record satisfies the annotation
type alias PersonAlias = { name : String, age : Int }
let a : PersonAlias = { name = "Alice", age = 30 }
a.nameUsing Enum
enum Direction
= North
| South
| East
| West
...
Value Label Enum
-- 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
-- Generate a ValueLabelSet from a ValueLabel enum
import ValueLabelSet
enum Gender
= Male(ValueLabel 1 "Male")
| Female(ValueLabel 2 "Female")...
Variant Data Circle
enum Shape
= Circle(Float)
| Rectangle(Float, Float)
fn area : Shape -> Float
fn area shape =...
Variant Data Rect
enum Shape
= Circle(Float)
| Rectangle(Float, Float)
fn area : Shape -> Float
fn area shape =...
Variant Record
enum User
= Guest
| Member { name : String, id : Int }
let user = User::Member { name = "Alice", id = 42 }
...
Valuelabel
Access
import ValueLabel
enum Gender
= Male(ValueLabel 1 "Male")
| Female(ValueLabel 2 "Female")
...
Create
import ValueLabel
let vl = ValueLabel.create 1 "Yes"
let v = ValueLabel.value vl
...
Query
import ValueLabel
enum Gender
= Male(ValueLabel 1 "Male")
| Female(ValueLabel 2 "Female")
...
Transform
import String
import ValueLabel
enum Gender
= Male(ValueLabel 1 "Male")
| Female(ValueLabel 2 "Female")...
Valuelabelset
Coverage
-- Check which values lack labels
import ValueLabelSet
let labels = ValueLabelSet.fromList [(1, "Agree"), (2, "Disagree")]
let result = ValueLabelSet.coverage [1, 2, 3] labels...
Create Lookup
-- Create a value label set and look up labels
import ValueLabelSet
let gender = ValueLabelSet.fromList [(1, "Male"), (2, "Female")]
ValueLabelSet.label 1 genderFrom Type
-- Create a ValueLabelSet from a ValueLabel enum type
import ValueLabelSet
enum Gender
= Male(ValueLabel 1 "Male")
| Female(ValueLabel 2 "Female")...
Merge Filter
-- Merge two label sets and check size
import ValueLabelSet
let base = ValueLabelSet.fromList [(1, "Low"), (2, "Medium")]
let extra = ValueLabelSet.fromList [(3, "High")]...
Reverse Lookup
-- Reverse lookup: find the code for a label
import ValueLabelSet
let gender = ValueLabelSet.fromList [(1, "Male"), (2, "Female")]
ValueLabelSet.value "Female" genderVariables
Declaring
let name = "Alice"
let age = 30
let pi = 3.14159
...
Let Expressions
let area =
let width = 10
let height = 5
width * height
area -- 50Multiple Bindings
let x = 1
let y = 2
let z = 3
...
Nested Destructuring
let (x, { a, b }) = (1, { a = 2, b = 3 })
a -- 2Polymorphic Let
-- A let-bound lambda can be used at multiple types (let-polymorphism)
let identity = |x| x
let n = identity 1
let s = identity "hello"
...
Record Destructuring
let { name, age } = { name = "Bob", age = 25 }
name -- "Bob"Recursive Let
-- Recursive lambdas bound with let
let fac = |n: Int| if n == 0 then 1 else n * fac (n - 1)
fac 5Scope
fn example : Int -> Int
fn example x =
let inner = x + 1
inner
inner -- Error: `inner` is not in scopeShadowing
let x = 10
let x = x + 5
x -- 15Shadowing Type Change
let x = 1
let x = x + 1
let x = "hello" -- x can change type when shadowed
...
Tuple Destructuring
let (x, y) = (10, 20)
x -- 10Type Annotations
let count : Int = 42
let message : String = "Hello"
let ratio : Float = 0.75
...