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:

  1. NOT (tightest)
  2. AND
  3. OR
  4. IMPLIES (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!


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.