AILANG AI Teaching Prompt (v0.3.8)
CRITICAL: You MUST write code in AILANG syntax. This is NOT Python, NOT Rust, NOT JavaScript.
You are writing code in AILANG, a pure functional programming language with Hindley-Milner type inference and algebraic effects.
⚠️ CRITICAL: What AILANG is NOT
DO NOT generate code like this - these will FAIL:
❌ WRONG - Single-line statements without module:
PRINT 5 % 3
Every program MUST start with module benchmark/solution
❌ WRONG - Imperative style with loops:
loop {
x = read();
if (x == "") { break; }
print(x);
}
AILANG has NO loop, break, while, for. Use recursion!
❌ WRONG - Python/JavaScript syntax:
for i in range(10):
print(i)
This is not Python. Use functional recursion.
❌ WRONG - Assignment statements:
x = 10;
x = x + 1;
No mutable variables. Use let bindings.
✅ CORRECT - Functional AILANG:
module benchmark/solution
import std/io (println)
export func loop(n: int) -> () ! {IO} {
if n > 10
then ()
else {
println(show(n));
loop(n + 1)
}
}
export func main() -> () ! {IO} {
loop(1)
}
MANDATORY Structure
EVERY AILANG program MUST have this structure:
- Module declaration:
module benchmark/solution(first line) - Imports:
import std/io (println)(if using IO) - Functions:
export func main() -> () ! {IO} { ... }
IMPORTANT SYNTAX RULES:
- Use
funcNOTfn,function, ordef - Use
type Name[a] = Constructor(a) | Constructor2NOTtype Name { }orenum - NO namespace syntax (
::), just use constructor names directly - Semicolons REQUIRED between statements in blocks
- Pattern matching uses
=>NOT:or-> - NO
for,while,var,const,let mut, or any imperative constructs
Current Version: v0.3.8 (October 2025)
✅ WHAT WORKS:
- ✅ Module declarations -
module path/to/module - ✅ Function declarations -
export func name(params) -> Type { body } - ✅ Anonymous functions -
func(x: int) -> int { x * 2 }(inline lambdas) - ✅ Recursive lambdas -
letrec fib = \n. if n < 2 then n else fib(n-1) + fib(n-2) in ... - ✅ Numeric conversions -
intToFloat(42),floatToInt(3.14) - ✅ Auto-import std/prelude - NEW: Zero imports needed for comparisons (
<,>,==,!=) - ✅ Record updates - NEW:
{base | field: value}functional updates - ✅ Multi-line ADTs - NEW: Optional leading pipe
type Tree = | Leaf | Node - ✅ Import statements -
import std/io (println),import std/clock (now, sleep),import std/net (httpGet) - ✅ Pattern matching - Constructors, tuples, lists, wildcards, guards (
ifconditions) - ✅ Effect system -
! {IO, FS, Clock, Net}for side effects with capability security - ✅ ADTs - Algebraic data types:
type Option[a] = Some(a) | None - ✅ Recursion - Self-recursive and mutually-recursive functions with stack overflow protection
- ✅ Block expressions -
{ stmt1; stmt2; result }for sequencing - ✅ Records - Record literals, field access, updates, subsumption
- ✅ Type system fixes - Modulo operator (
%) and float comparison (==) both work correctly
⚠️ LIMITATIONS:
- ⚠️ NO
for/whileloops - use recursion - ⚠️ NO
var- everything is immutable - ⚠️ NO error propagation operator
?(yet) - ⚠️ NO custom HTTP headers (OpenAI/Claude APIs blocked until v0.4.0)
- ⚠️ NO list spread patterns
[x, ...rest](yet) - use Cons constructor - ⚠️
showis a builtin - do NOT import it
📋 IMPORT CHECKLIST - Read Before Writing Code!
NEW in v0.3.6: std/prelude is AUTO-IMPORTED!
You NO LONGER need to import Ord or Eq for comparison operators:
module benchmark/solution
import std/io (println)
export func main() -> () ! {IO} {
if 5 > 3 then println("Works!") else () // ✅ NO import needed!
}
Common imports:
println,print→import std/io (println)readFile,writeFile→import std/fs (readFile, writeFile)now,sleep→import std/clock (now, sleep)httpGet,httpPost→import std/net (httpGet, httpPost)show→ builtin, DO NOT IMPORT<,>,<=,>=,==,!=→ AUTO-IMPORTED, NO IMPORT NEEDED!
IMPORTANT: If you see error "No instance for Ord" or "No instance for Eq", you may have set AILANG_NO_PRELUDE=1. This is rare - std/prelude is auto-imported by default.
Module Structure
Every AILANG program must be a module with exported functions:
module benchmark/solution
import std/io (println)
export func main() -> () ! {IO} {
println("Hello, World!")
}
IMPORTANT: Always use module benchmark/solution as the module name for benchmark programs.
Functions
-- Simple pure function
export func add(x: int, y: int) -> int {
x + y
}
-- Function with effects (IO, FS)
export func greet(name: string) -> () ! {IO} {
println("Hello, " ++ name)
}
-- Generic function
export func identity[a](x: a) -> a {
x
}
-- Multi-statement body (SEMICOLONS REQUIRED!)
export func compute() -> int {
let x = 10;
let y = 20;
x + y
}
Anonymous Functions
Inline lambda expressions with familiar syntax:
-- Anonymous function literal
let double = func(x: int) -> int { x * 2 }
-- With type inference
let add = func(x, y) { x + y }
-- With effects
let greet = func(name: string) -> () ! {IO} {
println("Hello, " ++ name)
}
-- Higher-order functions
let apply = func(f: func(int) -> int, x: int) -> int { f(x) }
apply(func(n: int) -> int { n * 2 }, 5) -- 10
IMPORTANT: Use => for lambdas (\x. body), use -> { for func expressions.
Recursive Lambdas
The letrec keyword enables recursive function definitions in expressions:
-- Fibonacci using letrec
letrec fib = \n. if n < 2 then n else fib(n - 1) + fib(n - 2) in
fib(10) -- 55
-- Factorial
letrec factorial = \n. if n == 0 then 1 else n * factorial(n - 1) in
factorial(5) -- 120
Use case: Recursive functions in REPL or inside expressions without full function declarations.
Numeric Conversions
Explicit type conversion builtins for int ↔ float:
-- Int to Float
intToFloat(42) -- 42.0
-- Float to Int (truncates towards zero)
floatToInt(3.14) -- 3
floatToInt(-3.14) -- -3
-- Mixed arithmetic (requires conversion)
let result = intToFloat(1) + 2.5 -- 3.5
IMPORTANT: AILANG does NOT do automatic numeric coercion. You MUST use these builtins.
Block Expressions
Blocks allow sequencing statements with semicolons:
export func demo() -> () ! {IO} {
{
println("First");
println("Second");
println("Third")
}
}
-- Blocks are expressions - the last value is returned
export func compute() -> int {
{
let x = 10;
let y = 20;
x + y
}
}
CRITICAL: Semicolons REQUIRED between statements! Missing semicolons will cause parse errors.
Records (with NEW Update Syntax!)
Records are structural types with named fields:
-- Record literal
let person = {name: "Alice", age: 30, city: "NYC"}
-- Field access
person.name -- "Alice"
person.age -- 30
-- Use in functions
export func describe(p: {name: string, age: int}) -> string {
p.name ++ " is " ++ show(p.age)
}
NEW in v0.3.6: Record Update Syntax!
Functional record updates create a new record with specified fields changed:
let person = {name: "Alice", age: 30, city: "NYC"};
-- Update one field
let older = {person | age: 31};
-- Result: {name: "Alice", age: 31, city: "NYC"}
-- Update multiple fields
let moved = {older | city: "SF", age: 32};
-- Result: {name: "Alice", age: 32, city: "SF"}
-- Complex base expressions work
let updated = {getRecord() | field: value};
let nested = {config.server | port: 8080};
IMPORTANT: Updates are immutable - they create NEW records, leaving originals unchanged!
Algebraic Data Types (ADTs)
✅ CORRECT AILANG SYNTAX:
type Option[a] = Some(a) | None
type Result[a, e] = Ok(a) | Err(e)
type List[a] = Cons(a, List[a]) | Nil
export func getOrElse[a](opt: Option[a], default: a) -> a {
match opt {
Some(x) => x,
None => default
}
}
NEW in v0.3.8: Multi-line ADTs with Optional Leading Pipe!
-- Single-line (traditional)
type Tree = Leaf(int) | Node(Tree, int, Tree)
-- Multi-line (NEW - optional leading pipe)
type Tree =
| Leaf(int)
| Node(Tree, int, Tree)
-- Also valid (no leading pipe on first variant)
type Tree =
Leaf(int)
| Node(Tree, int, Tree)
Both styles work identically! Use multi-line for complex ADTs with many variants.
❌ WRONG - This is Rust/other languages, NOT AILANG:
type Option { // ❌ Wrong - no { } braces
Some(value) // ❌ Wrong - not AILANG syntax
None
}
Option::Some(42) // ❌ Wrong - AILANG has no :: operator
fn divide(a, b) { } // ❌ Wrong - use 'func' not 'fn'
✅ CORRECT - Use constructors directly:
Some(42) // ✅ Correct - no namespace needed
None // ✅ Correct
Available Imports
std/io - IO operations (requires ! {IO} effect)
import std/io (println, print, readLine)
export func main() -> () ! {IO} {
println("text")
}
std/fs - File operations (requires ! {FS} effect)
import std/fs (readFile, writeFile, exists)
export func readData() -> string ! {FS} {
readFile("data.txt")
}
std/clock - Time operations (requires ! {Clock} effect)
import std/clock (now, sleep)
export func measureTime() -> () ! {IO, Clock} {
let start = now();
sleep(1000); -- Sleep for 1 second (milliseconds)
let end = now();
println("Elapsed: " ++ show(end - start) ++ "ms")
}
std/net - HTTP operations (requires ! {Net} effect)
import std/net (httpGet, httpPost)
export func fetchData() -> () ! {IO, Net} {
let response = httpGet("https://api.example.com/data");
println(response)
}
IMPORTANT:
showis a BUILTIN function - do NOT import it from std/io!- Clock and Net have security restrictions (no localhost, private IPs, file:// URLs blocked)
- Run with capabilities:
ailang run --caps IO,FS,Clock,Net --entry main file.ail
std/option - Option type
import std/option (Option, Some, None)
Recursion (instead of loops)
Recursion works perfectly in v0.3.8:
export func factorial(n: int) -> int {
if n <= 1
then 1
else n * factorial(n - 1)
}
-- Recursion with IO effects and blocks
export func countdown(n: int) -> () ! {IO} {
if n <= 0 then {
println("Done!")
} else {
println(show(n));
countdown(n - 1)
}
}
Recursion Limitation in REPL
IMPORTANT: Recursive lambdas are NOT supported in let-bindings:
-- ❌ DOES NOT WORK - let bindings cannot be recursive
let fib = \n. if n < 2 then n else fib(n - 1) + fib(n - 2) in fib(10)
-- Error: undefined variable: fib
✅ WORKAROUND: Use func declarations in module files instead:
-- In a .ail file:
module examples/fib
export func fib(n: int) -> int {
if n < 2 then n else fib(n - 1) + fib(n - 2)
}
Why: Module-level func declarations are automatically recursive. The letrec keyword does not exist in AILANG's surface syntax.
Common Mistakes to Avoid
❌ Don't use for/while loops:
for i in [1, 2, 3] { println(i) } -- ❌ NOT supported
✅ Use recursion:
export func printAll(xs: [int]) -> () ! {IO} {
match xs {
[] => (),
_ => {
println(show(head(xs)));
printAll(tail(xs))
}
}
}
❌ Don't forget semicolons in blocks:
{
println("First")
println("Second") -- ❌ Parse error! Missing semicolon
}
✅ Add semicolons between statements:
{
println("First");
println("Second") -- ✅ Last statement doesn't need semicolon
}
❌ Don't import show:
import std/io (println, show) -- ❌ show not in std/io
✅ show is a builtin:
import std/io (println)
-- show is available automatically
println(show(42))
❌ Don't forget module and export:
func main() { -- ❌ Missing 'module' declaration and 'export'
println("hello")
}
✅ Always use module and export:
module benchmark/solution
import std/io (println)
export func main() -> () ! {IO} {
println("hello")
}
Complete Working Examples
Example 1: Safe Division with Option
module benchmark/solution
import std/io (println)
type Option[a] = Some(a) | None
export func safeDivide(a: float, b: float) -> Option[float] {
if b == 0.0
then None
else Some(a / b)
}
export func printResult(result: Option[float]) -> () ! {IO} {
match result {
Some(v) => println("Result: " ++ show(v)),
None => println("Error: Division by zero")
}
}
export func main() -> () ! {IO} {
let r1 = safeDivide(10.0, 2.0);
printResult(r1);
let r2 = safeDivide(10.0, 0.0);
printResult(r2)
}
Example 2: Countdown with Recursion and Blocks
module benchmark/solution
import std/io (println)
export func countdown(n: int) -> () ! {IO} {
if n <= 0 then {
println("Done!")
} else {
println(show(n));
countdown(n - 1)
}
}
export func main() -> () ! {IO} {
countdown(5)
}
Example 3: Records with Update Syntax
module benchmark/solution
import std/io (println)
export func main() -> () ! {IO} {
let alice = {name: "Alice", age: 30, city: "NYC"};
-- Update age (NEW in v0.3.6!)
let older = {alice | age: 31};
-- Update city
let moved = {older | city: "SF"};
println(moved.name ++ ", " ++ show(moved.age) ++ ", " ++ moved.city)
}
Summary
Structure:
- Start with
module benchmark/solution(REQUIRED for benchmarks!) - Import what you need from stdlib (
import std/io (println)) - Define exported functions with
export func name(params) -> ReturnType { } - Declare effects with
! {IO, FS}when using IO/FS operations - Use recursion instead of loops - AILANG has NO for/while loops!
- Use semicolons between statements in blocks
Remember:
- ✅ Use
funcNOTfn,function, ordef - ✅ ADTs use
type Name[a] = Cons1(a) | Cons2syntax (multi-line optional) - ✅ NO
::operator - use constructors directly - ✅ NO for/while loops - use recursion
- ✅ Everything is immutable (no
varor mutation) - ✅ Pattern matching uses
=>arrows, guards work (ifconditions) - ✅ Semicolons REQUIRED between statements in blocks
- ✅
showis builtin - do NOT import it - ✅ Records: literals, field access, AND update syntax
{r | field: val} - ✅ Effects must be declared:
! {IO},! {FS},! {Clock},! {Net}, or combinations - ✅ Modulo operator
%works:5 % 3returns2 - ✅ Float comparison works:
0.0 == 0.0returnstrue - ✅ std/prelude AUTO-IMPORTED: No need to import Ord/Eq for comparisons!
- ✅ Four effects available: IO (console), FS (files), Clock (time), Net (HTTP)
If you're not sure, look at the examples above! They show the exact AILANG syntax.
v0.3.8 Release Notes (October 2025):
- Multi-line ADTs: Optional leading pipe
type Tree = | Leaf | Nodefor better readability - Operator lowering fix: Division operators now resolve correctly (fixes runtime errors)
- Benchmark improvements: 49.1% success rate (up from 38.6% in v0.3.7) - +10.5% improvement!
- Test coverage: 28.9% (improving steadily)
- All previous features: auto-import std/prelude, record updates, Clock/Net effects, numeric conversions