Module 3: Control Flow
In this module, you'll learn how to handle conditional logic, work with lists, and use boolean operators in L4.
Learning Objectives
By the end of this module, you will be able to:
- Write conditional expressions with IF/THEN/ELSE
- Use pattern matching with CONSIDER
- Work with lists using prelude functions
- Combine boolean conditions with AND, OR, NOT
- Understand operator precedence
Conditional Expressions
This is the complete working example to work along.
-- Module 3: Control Flow - Complete Examples
-- All examples are validated and use natural language identifiers
IMPORT prelude
-- =============================================================================
-- SECTION 1: Conditional Expressions
-- =============================================================================
-- Categorize a person's age
GIVEN age IS A NUMBER
GIVETH A STRING
`the age category` MEANS
IF age < 18
THEN "minor"
ELSE "adult"
-- Grade a score with nested conditionals
GIVEN score IS A NUMBER
GIVETH A STRING
`the letter grade` MEANS
IF score >= 90
THEN "A"
ELSE IF score >= 80
THEN "B"
ELSE IF score >= 70
THEN "C"
ELSE IF score >= 60
THEN "D"
ELSE "F"
-- Categorize an amount
GIVEN amount IS A NUMBER
GIVETH A STRING
`the amount category` MEANS
IF amount < 100
THEN "small"
ELSE IF amount < 1000
THEN "medium"
ELSE "large"
-- =============================================================================
-- SECTION 2: Boolean Logic
-- =============================================================================
-- Can a person vote?
GIVEN age IS A NUMBER
`is registered` IS A BOOLEAN
GIVETH A BOOLEAN
DECIDE `the person can vote` IF
age >= 18 AND `is registered`
-- Does a transaction need review?
GIVEN amount IS A NUMBER
`is high risk` IS A BOOLEAN
GIVETH A BOOLEAN
DECIDE `the transaction needs review` IF
amount > 10000 OR `is high risk`
-- Is the person a minor?
GIVEN age IS A NUMBER
GIVETH A BOOLEAN
DECIDE `the person is a minor` IF
NOT age >= 18
-- =============================================================================
-- SECTION 3: Working with Lists
-- =============================================================================
-- Check if all numbers are positive
GIVEN numbers IS A LIST OF NUMBER
GIVETH A BOOLEAN
DECIDE `all numbers are positive` IF
all (GIVEN n YIELD n > 0) numbers
-- Check if any number is negative
GIVEN numbers IS A LIST OF NUMBER
GIVETH A BOOLEAN
DECIDE `some number is negative` IF
any (GIVEN n YIELD n < 0) numbers
-- Get numbers greater than a threshold
GIVEN numbers IS A LIST OF NUMBER
threshold IS A NUMBER
GIVETH A LIST OF NUMBER
`numbers above threshold` MEANS
filter (GIVEN n YIELD n > threshold) numbers
-- =============================================================================
-- SECTION 4: Pattern Matching on Lists
-- =============================================================================
-- Describe a list
GIVEN items IS A LIST OF STRING
GIVETH A STRING
`describe the list` MEANS
CONSIDER items
WHEN EMPTY THEN "no items"
WHEN first FOLLOWED BY EMPTY THEN "one item"
WHEN first FOLLOWED BY rest THEN "multiple items"
-- =============================================================================
-- SECTION 5: Complex Eligibility Example
-- =============================================================================
-- A conviction record
DECLARE Conviction
HAS `the description` IS A STRING
`the conviction is spent` IS A BOOLEAN
-- A person with potential convictions
DECLARE Person
HAS `the person's name` IS A STRING
`the person's age` IS A NUMBER
`the person is bankrupt` IS A BOOLEAN
`the person's convictions` IS A LIST OF Conviction
-- Check if a person has an unspent conviction
GIVEN person IS A Person
GIVETH A BOOLEAN
DECIDE `the person has an unspent conviction` IF
any (GIVEN c YIELD c's `the conviction is spent` EQUALS FALSE) (person's `the person's convictions`)
-- Check if a person is eligible for a position
GIVEN person IS A Person
GIVETH A BOOLEAN
DECIDE `the person is eligible for the position` IF
person's `the person's age` >= 21
AND NOT person's `the person is bankrupt`
AND NOT `the person has an unspent conviction` person
-- =============================================================================
-- SECTION 6: Test Data
-- =============================================================================
-- Test lists
`positive numbers` MEANS LIST 1, 2, 3, 4, 5
`mixed numbers` MEANS LIST -1, 2, -3, 4
`empty list` MEANS LIST
`single item` MEANS LIST "apple"
`multiple items` MEANS LIST "apple", "banana", "cherry"
-- Test people
`spent conviction` MEANS Conviction "Minor offense 2010" TRUE
`unspent conviction` MEANS Conviction "Fraud 2023" FALSE
`eligible person` MEANS Person "Alice" 30 FALSE (LIST)
`bankrupt person` MEANS Person "Bob" 35 TRUE (LIST)
`person with unspent conviction` MEANS Person "Charlie" 40 FALSE (LIST `unspent conviction`)
`young person` MEANS Person "Diana" 19 FALSE (LIST)
-- =============================================================================
-- SECTION 7: Tests
-- =============================================================================
-- Conditional tests
#EVAL `the age category` 16
#EVAL `the age category` 25
#EVAL `the letter grade` 85
#EVAL `the amount category` 50
#EVAL `the amount category` 500
#EVAL `the amount category` 5000
-- Boolean tests
#EVAL `the person can vote` 21 TRUE
#EVAL `the person can vote` 16 TRUE
#EVAL `the person is a minor` 16
-- List tests
#EVAL `all numbers are positive` `positive numbers`
#EVAL `all numbers are positive` `mixed numbers`
#EVAL `some number is negative` `mixed numbers`
#EVAL `numbers above threshold` `positive numbers` 3
-- Pattern matching tests
#EVAL `describe the list` `empty list`
#EVAL `describe the list` `single item`
#EVAL `describe the list` `multiple items`
-- Eligibility tests
#EVAL `the person is eligible for the position` `eligible person`
#EVAL `the person is eligible for the position` `bankrupt person`
#EVAL `the person is eligible for the position` `person with unspent conviction`
#EVAL `the person is eligible for the position` `young person`
Basic IF/THEN/ELSE
GIVEN age IS A NUMBER
GIVETH A STRING
`the age category` MEANS
IF age < 18
THEN "minor"
ELSE "adult"
Every IF must have both THEN and ELSE branches—L4 requires you to handle all cases.
Nested Conditionals with BRANCH
GIVEN score IS A NUMBER
GIVETH A STRING
`grade` MEANS
BRANCH
IF score >= 90 THEN "A"
IF score >= 80 THEN "B"
IF score >= 70 THEN "C"
IF score >= 60 THEN "D"
OTHERWISE "F"
Conditional in Context
Conditionals are expressions—they can be used anywhere a value is expected:
message MEANS IF isActive THEN "Active" ELSE "Inactive"
Pattern Matching with CONSIDER
For more complex branching, especially with enumeration types, use CONSIDER:
GIVEN status IS A Status
GIVETH A STRING
`the status message` MEANS
CONSIDER status
WHEN Active THEN "The account is active"
WHEN Suspended reason THEN "Suspended: " + reason
WHEN Closed THEN "The account has been closed"
Pattern Matching on Lists
GIVEN items IS A LIST OF STRING
GIVETH A STRING
`describe the list` MEANS
CONSIDER items
WHEN EMPTY THEN "no items"
WHEN first FOLLOWED BY EMPTY THEN "one item"
WHEN first FOLLOWED BY rest THEN "multiple items"
The pattern first FOLLOWED BY rest destructures a list into its head and tail.
Boolean Logic
Basic Operators
| Operator | Meaning | Example |
|---|---|---|
AND or && |
Both must be true | a AND b |
OR or || |
At least one true | a OR b |
NOT |
Negation | NOT a |
IMPLIES or => |
If-then | a IMPLIES b |
Examples
-- AND: Both conditions must be true
DECIDE `the person can vote` IF age >= 18 AND isRegistered
-- OR: At least one condition must be true
DECIDE `the case needs review` IF amount > 10000 OR isHighRisk
-- NOT: Negation
DECIDE `the person is a minor` IF NOT age >= 18
-- IMPLIES: If first is true, second must be true
DECIDE `the rule holds` IF hasPermit IMPLIES paidFee
Operator Precedence
From highest to lowest precedence:
NOT(tightest)ANDORIMPLIES(loosest)
This means:
a OR b AND c -- means: a OR (b AND c)
NOT a AND b -- means: (NOT a) AND b
Use parentheses to make precedence explicit:
(a OR b) AND c -- clear: OR first, then AND
Comparison Operators
| Operator | Alternative | Meaning |
|---|---|---|
= |
EQUALS |
Equal to |
> |
GREATER THAN |
Greater than |
< |
LESS THAN |
Less than |
>= |
AT LEAST |
Greater than or equal |
<= |
AT MOST |
Less than or equal |
Examples
-- Numeric comparisons
age >= 18
amount LESS THAN 1000
score AT LEAST 70
-- String comparison
status EQUALS "Active"
name = "Alice"
-- Boolean comparison (often unnecessary)
isActive EQUALS TRUE -- same as just: isActive
isActive EQUALS FALSE -- same as: NOT isActive
Working with Lists
L4 provides prelude functions for working with lists. Note: You must IMPORT prelude to use these functions.
Creating Lists
numbers MEANS LIST 1, 2, 3, 4, 5
empty MEANS EMPTY
Common List Functions
| Function | Purpose | Example |
|---|---|---|
null |
Is empty? | null myList |
map |
Transform each | map f myList |
filter |
Keep matching | filter f myList |
all |
All satisfy? | all f myList |
any |
Any satisfy? | any f myList |
elem |
Check membership | elem 3 myList |
Using Quantifiers
-- All elements positive?
all (GIVEN n YIELD n > 0) numbers
-- Any element negative?
any (GIVEN n YIELD n < 0) numbers
The GIVEN ... YIELD creates an anonymous function (lambda).
Important: Parentheses with Field Access
When passing field access to functions, use parentheses:
-- ❌ Wrong: Parser confusion
all (GIVEN g YIELD g's age >= 18) charity's governors
-- ✅ Right: Parentheses around the list argument
all (GIVEN g YIELD g's age >= 18) (charity's governors)
This is one of the most common mistakes in L4!
Combining Conditions in Legal Rules
GIVEN person IS A Person
charity IS A `Registered Charity`
DECIDE `the person can be a governor` IF
person's age >= 18
AND NOT person's `is bankrupt`
AND NOT any (GIVEN c YIELD NOT c's `is spent`) (person's convictions)
Real-World Example: Eligibility Check
-- Helper: Check for unspent convictions
GIVEN person IS A Person
GIVETH A BOOLEAN
`the person has an unspent conviction` MEANS
any (GIVEN c YIELD c's `is spent` EQUALS FALSE) (person's convictions)
-- Main eligibility rule
GIVEN person IS A Person
GIVETH A BOOLEAN
DECIDE `the person is eligible for the position` IF
person's age >= 21
AND NOT person's `is bankrupt`
AND NOT `the person has an unspent conviction` person
Exercises
Exercise 1: Nested Conditional
Write a function that categorizes an amount as "small" (< 100), "medium" (100-999), or "large" (>= 1000).
Exercise 2: List Validation
Write a function that checks if all items in a list of numbers are positive. (Remember to IMPORT prelude.)
Exercise 3: Complex Condition
Write a rule: "A person can purchase alcohol if they are at least 21, have valid ID, and are not on the banned list."
Common Mistakes
1. Missing ELSE
-- ❌ Wrong: No ELSE branch
result MEANS IF condition THEN "yes"
-- ✅ Right: Both branches required
result MEANS IF condition THEN "yes" ELSE "no"
2. Precedence Confusion
-- ❌ Confusing: What does this mean?
a OR b AND c IMPLIES d
-- ✅ Clear: Use parentheses
(a OR (b AND c)) IMPLIES d
3. Forgetting Parentheses with Functions
-- ❌ Wrong: Parser error
length person's items > 0
-- ✅ Right: Parentheses around field access
length (person's items) > 0
4. Forgetting to IMPORT prelude
Functions like all, any, filter, map require IMPORT prelude.
Summary
| Concept | Syntax |
|---|---|
| Conditional | IF condition THEN result1 ELSE result2 |
| Pattern match | CONSIDER expr WHEN pattern THEN result |
| List destructure | WHEN first FOLLOWED BY rest THEN ... |
| Boolean AND | condition1 AND condition2 |
| Boolean OR | condition1 OR condition2 |
| Boolean NOT | NOT condition |
| Check all | all (GIVEN x YIELD condition) list |
| Check any | any (GIVEN x YIELD condition) list |
| List membership | elem item list |
What's Next?
In Module 4: Functions, you'll learn how to define reusable functions, use local definitions with WHERE, and build more complex computations.