Version: Current Implementation Status
Last Updated: November 22, 2025
This document provides a comprehensive reference for all Cure language features, including current implementation status, syntax examples, and usage patterns.
module ModuleName do
import Std [abs/1, sqrt/1, Option, Result]
import Std.Math [sin/1, cos/1]
export [main/0, demo_function/1]
# Module contents...
end
# Simple function
def add(x: Int, y: Int): Int = x + y
# Function with complex body
def demo(): Unit =
let result = calculate_something()
println("Result: " <> show(result))
0
# Helper function
def helper(x: Int): String = int_to_string(x)
# Simple lambda
let double = fn(x) -> x * 2 end
# Lambda with pattern matching instead of if-then-else
let safe_div = fn(x, y) ->
match y == 0 do
true -> error("Division by zero")
false -> ok(x / y)
end
end
# Lambda with multiple parameters
let fold_sum = fold(numbers, 0, fn(x, acc) -> x + acc end)
match expression do
Ok(value) -> handle_success(value)
Error(msg) -> handle_error(msg)
end
match list do
[] -> "empty"
[x] -> "single: " <> show(x)
[x | rest] -> "head: " <> show(x) <> ", rest: " <> show(rest)
end
match option do
Some(found) -> "Found: " <> show(found)
None -> "Not found"
end
Cure supports case expressions as an alternative to match (they are semantically identical):
# Case with 'of' keyword
case expression of
Ok(value) -> handle_success(value)
Error(msg) -> handle_error(msg)
end
# Functionally equivalent to match
match expression do
Ok(value) -> handle_success(value)
Error(msg) -> handle_error(msg)
end
Note: Cure does not have if-then-else expressions. Use match or case for conditional logic.
# Simple let
let x = 42
# Let with complex expression
let result = calculate()
|> map(fn(x) -> x * 2 end)
|> filter(fn(x) -> x > 10 end)
result = input
|> transform1()
|> transform2(argument)
|> final_transform()
Int: 64-bit signed integersFloat: 64-bit IEEE floating-point numbers String: UTF-8 encoded text stringsBool: Boolean values (true, false)Atom: Symbolic constants (:atom_name)Binary: Byte sequencesUnit: Unit type for functions with no return valueNat: Natural numbers (Int >= 0) - refinement typePos: Positive integers (Int > 0) - refinement typePid: BEAM process identifierList(T) # Homogeneous lists
List(T, n) # Length-indexed lists (dependent type)
Tuple(T1, T2, ...) # Fixed-size tuples
Result(T, E) # Error handling without exceptions
Option(T) # Nullable values
Ok(value) # Success result
Error(message) # Error result
Some(value) # Present optional value
None # Absent optional value
# Length-indexed types
Vector(T, n: Nat) # Fixed-length vector
List(T, n: Nat) # List with compile-time known length
Matrix(rows: Nat, cols: Nat, T) # 2D matrix with dimensions
# Constraint-based types
{x: Int | x > 0} # Positive integers
{x: Float | x >= 0.0} # Non-negative floats
{xs: List(T) | length(xs) > 0} # Non-empty lists
# Function-dependent types
def replicate(n: Nat, x: T): List(T, n) # Return type depends on argument
def safe_head(xs: List(T, n)): T when n > 0 # Precondition constraint
+, -, *, /, %==, !=, <, >, <=, >=<> (concatenation)| (cons operator, used in [h | t] syntax)|> (function composition)+x, -xnot(expr)42 # Integer
3.14 # Float
-5 # Negative integer
"Hello, World!" # Simple string
"Line 1\nLine 2" # String with escape sequences
"Quote: \"text\"" # String with escaped quotes
[] # Empty list
[1, 2, 3] # List of integers
["a", "b", "c"] # List of strings
Tuples use curly brace {} syntax:
{} # Empty tuple (Unit)
{42} # Single element tuple
{1, "hello", true} # Multi-element tuple
{:ok, "success"} # Tagged tuple (atom + value)
{:error, "failed"} # Error tuple (atom + value)
Note: Tuple pattern matching is fully supported:
match point do
{x, y} when x > 0.0 and y > 0.0 -> "First quadrant"
{x, y} when x == 0.0 and y == 0.0 -> "Origin"
_ -> "Other quadrant"
end
:atom_name
:increment
:ok
Cure provides first-class support for finite state machines with compile-time verification, state-dependent data, and integration with the BEAM actor model.
Cure FSMs use a record-based payload system with arrow transition syntax:
# Define a payload record to track FSM data
record TrafficPayload do
cycles_completed: Int
timer_events: Int
emergency_stops: Int
end
# FSM with initial payload values
fsm TrafficPayload{cycles_completed: 0, timer_events: 0, emergency_stops: 0} do
Red --> |timer| Green
Red --> |emergency| Red # Self-transition
Green --> |timer| Yellow
Green --> |emergency| Red
Yellow --> |timer| Red
Yellow --> |emergency| Red
end
Key Points:
- First state in transitions is the initial state (Red in this example)
- Transitions use --> arrow with |event| syntax
- Must define a payload record even if fields are unused
FSMs compile to BEAM gen_statem processes:
import Std.Fsm [fsm_spawn/2, fsm_cast/2, fsm_advertise/2, fsm_state/1]
import Std.Pair [pair/2]
# Spawn an FSM instance with initial data
let initial_data = TrafficPayload{cycles_completed: 0, timer_events: 0, emergency_stops: 0}
let fsm_pid = fsm_spawn(:TrafficPayload, initial_data)
# Give the FSM a name for easy reference
let adv_result = fsm_advertise(fsm_pid, :traffic_light)
# Send events to the FSM
let empty_list = []
let event = pair(:timer, empty_list)
let cast_result = fsm_cast(:traffic_light, event)
# Query current state
let current_state = fsm_state(:traffic_light) # Returns current state atom
Cure FSMs compile to Erlang gen_statem behaviors with the following features:
Compile-Time Verification:
- State machine structure validated at compile time
- Transition completeness checked
- Event type checking
Runtime Integration:
- Native BEAM process integration
- Mailbox-based event handling
- OTP supervision tree compatible
- Hot code reloading support
Current Implementation:
- Simple arrow-based transition syntax (State1 --> |event| State2)
- Record-based payload data tracking
- Event casting with atom-based event names
- State querying via FSM references
record Person do
name: String
age: Nat
email: String
end
# Creating records
let person = Person{name: "Alice", age: 30, email: "alice@example.com"}
# Pattern matching on records
match person do
Person{name: name, age: age} when age >= 18 ->
"Hello, adult " <> name <> "!"
Person{name: name} ->
"Hello, young " <> name <> "!"
end
# Length-indexed types
Vector(T, n: Nat) # Fixed-length vector
List(T, n: Nat) # List with known length
Range(min: Int, max: Int) # Integer range type
# Matrix with dimension checking
record Matrix(rows: Nat, cols: Nat, T) do
data: Vector(Vector(T, cols), rows)
end
# Refinement types
type NonEmptyList(T) = List(T, n) when n > 0
def head(list: NonEmptyList(T)): T =
match list do
[x|_] -> x
# No need for empty case - type system guarantees non-empty
end
import ModuleName [
function1/1, # Function with 1 parameter
function2/2, # Function with 2 parameters
TypeName, # Type import
constructor # Constructor import
]
# Nested lambdas in higher-order functions
processed = data
|> filter(fn(item) -> not(is_empty(item)) end)
|> map(fn(item) ->
process_item(item)
|> validate()
|> transform()
end)
|> collect_results()
Both match and case are supported and functionally equivalent:
# Case expression with 'of' keyword (alternative to match)
case expression of
Ok(value) -> handle_success(value)
Error(msg) -> handle_error(msg)
end
case list of
[] -> "empty"
[x] -> "single: " <> show(x)
[x | rest] -> "head: " <> show(x)
end
match value do
x when x > 0 -> "positive"
x when x < 0 -> "negative"
_ -> "zero"
end
# Guards in case expressions
case number do
n when n > 100 -> "large"
n when n > 10 -> "medium"
_ -> "small"
end
Cure supports guards on function definitions with when clauses, enabling elegant multi-clause functions with preconditions:
# Basic guard on function parameter
def is_positive(x: Int): Bool when x > 0 = true
def is_positive(_x: Int): Bool = false
# Multi-clause function with guards
def abs(x: Int): Int when x >= 0 = x
def abs(x: Int): Int = 0 - x
# Sign function with complete coverage
def sign(x: Int): Int when x > 0 = 1
def sign(x: Int): Int when x == 0 = 0
def sign(x: Int): Int = -1
# Guards with AND/OR sequences
def in_range(x: Int, min: Int, max: Int): Bool
when x >= min and x <= max = true
def in_range(_x: Int, _min: Int, _max: Int): Bool = false
def is_extreme(x: Int): Bool
when x > 100 or x < -100 = true
def is_extreme(_x: Int): Bool = false
# Real-world example: tax brackets
def tax_rate(income: Int): Float when income <= 10000 = 0.0
def tax_rate(income: Int): Float
when income > 10000 and income <= 40000 = 0.1
def tax_rate(income: Int): Float
when income > 40000 and income <= 100000 = 0.2
def tax_rate(_income: Int): Float = 0.3
Guard Features:
- All comparison operators: >, <, >=, <=, ==, !=
- Logical combinations: and, or
- Type refinement: Guards narrow parameter types in function bodies
- SMT verification: Guards verified for completeness and consistency
- Coverage analysis: Compiler detects unreachable clauses
- Optimization: Guard-specific optimizations for performance
Example: Comprehensive Guards Demo
See examples/06_comprehensive_guards_demo.cure for a complete demonstration including:
- Basic comparisons with all operators
- Multi-clause functions
- Guard sequences (AND/OR combinations)
- Type refinement examples
- Real-world applications (discounts, tax brackets, shipping costs)
- Recursive functions with guards
- Performance-ordered guard clauses
def safe_operation(input: Int): Result(Int, String) =
match input < 0 do
true -> error("Negative input not allowed")
false -> ok(input * 2)
end
def find_item(list: List(String), target: String): Option(String) =
match search(list, target) do
found when found != "" -> Some(found)
_ -> None
end
Use pipe operators for readable data transformations:
result = input
|> validate_input()
|> process_data()
|> format_output()
Use Result types for operations that can fail:
def divide(x: Float, y: Float): Result(Float, String) =
match y == 0.0 do
true -> error("Division by zero")
false -> ok(x / y)
end
Prefer pattern matching for control flow:
# Good - using pattern matching
match result do
Ok(value) -> use_value(value)
Error(msg) -> handle_error(msg)
end
# Also good - using case
case result of
Ok(value) -> use_value(value)
Error(msg) -> handle_error(msg)
end
Cure supports type classes for ad-hoc polymorphism and constraint-based programming.
typeclass Ord(T) where
def compare(x: T, y: T): Ordering
def (<)(x: T, y: T): Bool = compare(x, y) == LT
def (<=)(x: T, y: T): Bool = compare(x, y) != GT
end
typeclass Show(T) where
def show(x: T): String
end
typeclass Functor(F) where
def map(f: A -> B, fa: F(A)): F(B)
end
# Manual instances
instance Ord(Int) where
def compare(x, y) =
if x < y then LT
else if x > y then GT
else EQ
end
end
# Automatic derivation
derive Ord for List(T) when Ord(T)
derive Show for Option(T) when Show(T)
derive Functor for List
derive Functor for Option
# Generic sorting with constraints
def sort(xs: List(T)): List(T) where Ord(T) =
quicksort_impl(xs)
# Pretty printing with constraints
def debug_print(x: T): Unit where Show(T) =
print(show(x))
# Functor mapping
def transform(f: A -> B, container: F(A)): F(B) where Functor(F) =
map(f, container)
# Function types that depend on their arguments
def replicate(n: Nat, x: T): List(T, n) =
if n == 0 then [] else x :: replicate(n-1, x)
# Pairs where the second type depends on the first value
{x: Nat, Vector(Int, x)} # Pair of number and vector of that length
# Types with predicates
{x: Int | x > 0} # Positive integers
{x: List(T) | length(x) > 0} # Non-empty lists
# Types parameterized by values
Vector(T, n: Nat) # Vector of type T with length n
Matrix(rows: Nat, cols: Nat, T) # Matrix with compile-time dimensions
Cure provides a sophisticated command-line interface with wrapper script automation and intelligent build management.
# Special wrapper script commands
cure build # Execute 'make all' to build compiler
cure test # Execute 'make test' to run test suite
cure clean # Execute 'make clean' to clean build artifacts
cure shell # Start Erlang development shell with modules loaded
# Basic compilation
cure input.cure # Compile with defaults
cure input.cure -o output.beam # Specify output file
cure input.cure --verbose # Verbose compilation
cure input.cure --no-optimize # Disable optimizations
Cure includes a comprehensive standard library implemented in Cure itself with Erlang runtime support.
# Import common types and functions
import Std [Result, Option, ok, error, some, none]
import Std [map/2, filter/2, fold_left/3, fold_right/3]
# Mathematical operations
import Std.Math [abs/1, sqrt/1, sin/1, cos/1, pi, e]
# String operations
import Std.String [length/1, concat/2, split/2, trim/1]
# FSM utilities
import Std.FSM [create/2, send_event/2, get_state/1]
# Chainable error handling
result = safe_divide(x, y)
|> map_ok(fn(val) -> val * 2 end)
|> and_then(fn(doubled) -> safe_sqrt(doubled) end)
match result do
Ok(final_value) -> println("Success: " <> show(final_value))
Error(msg) -> println("Error: " <> msg)
end
# Optional value handling
opt_value = find_in_list(items, predicate)
|> map(fn(item) -> process(item) end)
|> filter(fn(processed) -> is_valid(processed) end)
Cure includes comprehensive testing infrastructure covering all aspects of the compiler and standard library.
# Master test runner for all new CLI and stdlib tests
erl -pa _build/ebin -pa test -s run_all_new_tests run -s init stop
# Individual comprehensive test suites
erl -pa _build/ebin -pa test -s cli_wrapper_comprehensive_test run -s init stop
erl -pa _build/ebin -pa test -s cure_wrapper_script_test run -s init stop
cure_lexer.erl)cure_parser.erl)cure_typechecker.erl)cure_type_optimizer.erl)cure_codegen.erl, cure_beam_compiler.erl)Cure's type system enables aggressive optimizations:
# Before optimization (polymorphic)
def map(f: T -> U, xs: List(T)): List(U) = ...
# After monomorphization (specialized for Int -> String)
def map_Int_String(f: Int -> String, xs: List(Int)): List(String) =
# Optimized implementation for specific types
specialized_map_impl(f, xs)
This reference covers all currently implemented language features and provides insight into Cure's unique combination of dependent types, native FSM support, and BEAM integration.