# AILANG Documentation for LLMs This file contains all AILANG documentation in a single file for LLM consumption. Last updated: $(date -u +"%Y-%m-%d %H:%M:%S UTC") --- # README # 🧠 AILANG: The Deterministic Language for AI Coders ![CI](https://github.com/sunholo-data/ailang/workflows/CI/badge.svg) ![Coverage](https://img.shields.io/badge/coverage-39.1%25-orange.svg) ![Go Version](https://img.shields.io/badge/go-%3E%3D1.22-blue.svg) ![License](https://img.shields.io/badge/license-Apache%202.0-green.svg) AILANG is a purely functional, effect-typed language designed as a **deterministic execution and evaluation substrate** for AI-generated code. Unlike human-oriented languages built around IDEs, concurrency, and sugar, AILANG's design goal is **machine decidability, semantic transparency, and compositional determinism**. AILANG exists to ensure that when AI systems improve themselves, the improvement is real. --- ## 🧩 Core Philosophy **For humans, a language is a tool for expression.** **For AIs, it's a substrate for reasoning.** AILANG minimizes ambiguity and maximizes predictability. Every construct — type, effect, or expression — has **deterministic semantics** that can be reflected, verified, and serialized. ## What AILANG Is (and Is Not) AILANG is **not** an autonomous agent framework. AILANG is **not** a productivity language for humans. AILANG **is**: - A deterministic semantic substrate for AI-generated programs - An evaluation harness where reasoning, testing, and execution align - A language where programs can be safely re-written, re-run, and compared by machines Autonomous agents, self-training loops, and reflective rewriting are **enabled by AILANG’s guarantees**, not embedded as opaque runtime behavior. Further reading on answering common misconceptions: - AILANG is not another AI framework. - AILANG is not trying to be a "better python" - AILANG as a Semantic Control Surface Read more about [AILANG vs Agents](docs/docs/guides/ailang-vs-agents.mdx) concepts. ## 🏗️ Architecture AILANG is built in layers, from stable foundations to cutting-edge features: **Stable Core:** - Pure functional semantics with algebraic data types (ADTs) - Hindley-Milner type inference with row polymorphism - Effect system with capability-based security (IO, FS, Net, Clock) - Deterministic evaluator with explicit effect tracking **In Development:** - Reflection & meta-programming (typed quasiquotes, structural type classes — design complete, implementation in progress) - Deterministic tooling (normalize, suggest-imports, trace export) - Schema registry for machine-readable type definitions For detailed architecture documentation, see [docs/architecture/](docs/architecture/) ## 🔮 Vision & Roadmap AILANG aims to be the first language optimized for autonomous AI code synthesis. Our roadmap focuses on: - **Deterministic tooling** - Canonical formatting, import suggestion, trace export - **Reflection & meta-programming** - Typed quasiquotes, structural type classes - **Schema registry** - Machine-readable type/effect definitions - **Cognitive autonomy** - Full round-trip reasoning with machine-verifiable self-modification loops For detailed roadmap and design philosophy, see: - [VISION.md](docs/VISION.md) - Long-term vision and design principles - [CHANGELOG.md](CHANGELOG.md) - Completed features and upcoming releases --- ## 💡 Why AILANG Works Better for AIs | Human Need | Human Feature | AI Equivalent in AILANG | |-----------|---------------|------------------------| | IDE assistance | LSP / autocompletion | Deterministic type/query API | | Asynchronous code | Threads / goroutines | Static task DAGs with effects | | Code reuse | Inheritance / traits | Structural reflection & records | | Debugging | Interactive debugger | Replayable evaluation trace | | Logging | `print` / `console` | `--emit-trace jsonl` structured logs | | Macros | text substitution | Typed quasiquotes (semantic macros - (planned - v0.6+) | --- ## 🔁 Why AILANG Has No Loops (and Never Will) AILANG intentionally omits `for`, `while`, and other open-ended loop constructs. This isn't a missing feature — it's a design decision rooted in **determinism and compositional reasoning**. ### 🧠 For Humans, Loops Express Control. For AIs, Loops Obscure Structure. Traditional loops compress time into mutable state: ```python sum = 0 for i in range(0, 10): sum = sum + i ``` This is compact for humans but **semantically opaque** for machines: the iteration count, state shape, and termination guarantee are **implicit**. AILANG replaces this with **total, analyzable recursion**: ```ailang foldl(range(0, 10), 0, \acc, i. acc + i) ``` or **pattern matching**: ```ailang func sum(list: List[Int]) -> Int { match list { [] => 0, [x, ...xs] => x + sum(xs) } } ``` Every iteration is a **pure function over data, not time** — which makes it statically decidable, effect-safe, and perfectly compositional. ### ⚙️ The Deterministic Iteration Principle | Goal | Imperative Loops | AILANG Alternative | |------|-----------------|-------------------| | Repeat a computation | `for` / `while` | `map`, `fold`, `filter`, `rec` | | Aggregate results | mutable accumulator | `foldl` / `foldr` | | Early termination | `break` | `foldWhile` / `find` | | Parallel evaluation | scheduler threads | static task DAGs | | Verification | undecidable | total + effect-typed | ### 🧩 Benefits - **Deterministic semantics**: iteration defined by data, not by time - **Static totality**: no halting ambiguity - **Composable reasoning**: works algebraically with higher-order functions - **Easier optimization**: map/fold can fuse or parallelize safely - **Simpler runtime**: no mutable counters or loop scopes **No hidden state. No implicit time. Fully analyzable by both compiler and AI.** For the formal rationale and algebraic laws, see the [Why No Loops?](https://ailang.sunholo.com/docs/reference/no-loops) documentation. --- ## Quick Start ### Installation for AI Agents (Recommended) AILANG is designed to be used with AI coding agents. Install via your agent's extension/plugin system: **Claude Code:** ``` /plugin marketplace add sunholo-data/ailang_bootstrap /plugin install ailang ``` **Gemini CLI:** ```bash gemini extensions install https://github.com/sunholo-data/ailang_bootstrap.git ``` These plugins provide: - AILANG binary (auto-installed) - MCP tools for type-checking and running code - Custom slash commands (`/ailang:prompt`, `/ailang:run`, etc.) - Teaching prompts and coding challenges - Full stdlib documentation via `ailang builtins list --verbose` ### Manual Installation For standalone CLI usage or development: ```bash # macOS (Apple Silicon) curl -L https://github.com/sunholo-data/ailang/releases/latest/download/ailang-darwin-arm64.tar.gz | tar -xz sudo mv ailang /usr/local/bin/ # macOS (Intel) curl -L https://github.com/sunholo-data/ailang/releases/latest/download/ailang-darwin-amd64.tar.gz | tar -xz sudo mv ailang /usr/local/bin/ # Linux curl -L https://github.com/sunholo-data/ailang/releases/latest/download/ailang-linux-amd64.tar.gz | tar -xz sudo mv ailang /usr/local/bin/ # From source git clone https://github.com/sunholo-data/ailang.git cd ailang && make install # Verify ailang --version ``` For detailed instructions, see the [Getting Started Guide](https://ailang.sunholo.com/docs/guides/getting-started). ### MCP Server (For Custom Integrations) If you want to integrate AILANG tools into other AI systems via [Model Context Protocol](https://modelcontextprotocol.io/): ```bash # Clone the bootstrap repo git clone https://github.com/sunholo-data/ailang_bootstrap.git cd ailang_bootstrap/mcp-server # Install dependencies and start server npm install npm start ``` Configure in your MCP client's `settings.json`: ```json { "mcpServers": { "ailang-tools": { "command": "node", "args": ["/path/to/ailang_bootstrap/mcp-server/server.js"] } } } ``` **Available MCP Tools:** | Tool | Description | |------|-------------| | `ailang_prompt` | Get teaching prompt (SOURCE OF TRUTH for syntax) | | `ailang_check` | Type-check a file | | `ailang_run` | Run with capabilities | | `ailang_builtins` | Full stdlib docs with examples | | `ailang_eval` | Evaluate expression in REPL | ### Hello World (Module Execution) ```ailang -- examples/demos/hello_io.ail module examples/demos/hello_io import std/io (println) export func main() -> () ! {IO} { println("Hello from AILANG v0.3.14!") } ``` ```bash ailang run --caps IO examples/demos/hello_io.ail # Output: Hello from AILANG v0.3.14! ``` ### Interactive REPL The REPL features full type inference and deterministic evaluation: ```bash ailang repl λ> 1 + 2 3 :: Int λ> "Hello " ++ "World" Hello World :: String λ> let double = \x. x * 2 in double(21) 42 :: Int λ> :type \x. x + x \x. x + x :: ∀α. Num α ⇒ α → α λ> :quit ``` **REPL Commands**: `:help`, `:type `, `:instances`, `:import `, `:history`, `:clear` See [REPL Commands](docs/reference/repl-commands.md) for full reference. ### Property-Based Testing AILANG includes QuickCheck-style property-based testing for deterministic validation: ```ailang // Unit tests test "addition works" = 1 + 1 == 2 // Property tests (100 random cases) property "addition commutes" (x: int, y: int) = x + y == y + x property "list reversal" (xs: list(int)) = reverse(reverse(xs)) == xs ``` Run tests: ```bash ailang test examples/testing_basic.ail ``` Output: ``` → Running tests in examples/testing_basic.ail Test Results Module: All Tests Tests: ✓ addition works Properties: ✓ addition commutes (100 cases) ✓ list reversal (100 cases) ✓ All tests passed 3 tests: 3 passed, 0 failed, 0 skipped (0.3s) ``` **Features**: - **Automatic shrinking**: When a property fails, finds minimal counterexample - **Configurable generation**: Control ranges, sizes, and random seeds - **CI/CD integration**: JSON output, exit codes, GitHub Actions examples - **Type-aware generators**: Built-in support for all AILANG types **Examples**: - [Basic testing examples](examples/testing_basic.ail) - Unit tests and simple properties - [Advanced testing examples](examples/testing_advanced.ail) - ADTs, trees, algebraic laws **Documentation**: - [Testing Guide](docs/TESTING.md) - Complete user documentation - [AI Testing Guide](prompts/testing_guide_ai.md) - Property patterns for AI agents --- ## What AILANG Can Do (Implementation Status) ### ✅ Core Language - **Pure functional programming** - Lambda calculus, closures, recursion - **Hindley-Milner type inference** - Row polymorphism, let-polymorphism - **Built-in type class instances** - `Num`, `Eq`, `Ord`, `Show` (structural reflection planned for future release) - **Algebraic effects** - Capability-based security (IO, FS, Clock, Net) - **Pattern matching** - ADTs with exhaustiveness checking - **Module system** - Runtime execution, cross-module imports - **Block expressions** - `{ e1; e2; e3 }` for sequencing - **JSON support** - Parsing (`std/json.decode`), encoding (`std/json.encode`) ### ✅ Development Tools - **M-EVAL** - AI code generation benchmarks (multi-model support) - **M-EVAL-LOOP v2.0** - Native Go eval tools with 90%+ test coverage - **Structured error reporting** - JSON schemas for deterministic diagnostics - **Effect system runtime** - Hermetic testing with `MockEffContext` ## AILANG as an Evaluation Harness AILANG is intentionally designed to host AI evaluation loops: - Deterministic execution - Replayable traces - Property-based testing - Comparable outputs across models M-EVAL is not a benchmark bolted onto the language — it is evidence that the language semantics are stable enough to reason about AI performance itself. ### 🔜 In Development See [design documents](design_docs/planned/) for upcoming features and development roadmap. See **[Full Implementation Status](https://ailang.sunholo.com/docs/examples#implementation-status)** for detailed breakdown with auto-updated table of all examples. --- ## 🔗 Go Interop (v0.5.x) AILANG can compile to Go for game development and performance-critical applications: ```bash # Generate Go code from AILANG ailang compile --emit-go --package-name game world.ail ``` **Features:** - Type generation (records → Go structs) - Extern function stubs (implement in Go) - Deterministic output (fixed seeds) **ABI Stability (v0.5.x):** The Go interop ABI is "stable preview": - Primitive type mapping is stable - Record/struct generation is stable - Breaking changes announced in CHANGELOG - Full stability guaranteed in v0.6.0 📖 See **[Go Interop Guide](docs/docs/guides/go-interop.md)** for complete documentation. --- ## Documentation 📖 **[Complete Documentation](https://ailang.sunholo.com/)** - Visit our full documentation site **Quick Links:** - **[Vision](https://ailang.sunholo.com/docs/vision)** - Why AILANG exists and what makes it different - **[Examples](https://ailang.sunholo.com/docs/examples)** - Interactive code examples with explanations - **[Getting Started](https://ailang.sunholo.com/docs/guides/getting-started)** - Installation and tutorial - **[Language Reference](https://ailang.sunholo.com/docs/reference/language-syntax)** - Complete syntax guide - **[Benchmarks](https://ailang.sunholo.com/docs/benchmarks/performance)** - AI code generation metrics (49% improvement) --- ## Development **Quick commands:** ```bash make install # Build and install make test # Run all tests make repl # Start REPL make run FILE= # Run example file ``` **For detailed workflows and contribution guidelines:** - [Development Guide](https://ailang.sunholo.com/docs/guides/development) - [CONTRIBUTING.md](docs/CONTRIBUTING.md) - [CLAUDE.md](CLAUDE.md) - Instructions for AI development assistants --- ### Project Structure ``` ailang/ ├── cmd/ailang/ # CLI entry point ├── internal/ # Core implementation │ ├── repl/ # Interactive REPL │ ├── lexer/ # Tokenizer │ ├── parser/ # Parser │ ├── types/ # Type system │ ├── eval/ # Evaluator │ ├── effects/ # Effect system runtime │ ├── builtins/ # Builtin registry │ └── eval_harness/ # AI evaluation framework ├── stdlib/ # Standard library ├── examples/ # Example programs ├── docs/ # Documentation └── design_docs/ # Design documents ``` --- ## Contributing AILANG is an experimental language in active development. Contributions are welcome! Please see the [Development Guide](https://ailang.sunholo.com/docs/guides/development) for guidelines. --- ## ⚖️ License & Philosophy AILANG is **open infrastructure for Cognitive DevOps** — systems that write, test, and deploy themselves deterministically. **Our design north star: build languages AIs enjoy using.** Apache 2.0 - See [LICENSE](LICENSE) for details. --- ## Acknowledgments AILANG draws inspiration from: - **Haskell** (type system, purity) - **OCaml** (module system, effects) - **Rust** (capability-based security) - **Idris/Agda** (reflection and metaprogramming) --- *For AI agents: This is a deterministic functional language with Hindley-Milner type inference, algebraic effects, and explicit effect tracking. The REPL is fully functional. Module execution works with capability-based security. See [CLAUDE.md](CLAUDE.md) and [Complete Documentation](https://ailang.sunholo.com/) for exact capabilities.* --- # Guide: wasm-integration.md --- id: wasm-integration title: WebAssembly Integration Guide sidebar_label: WASM Integration --- # WebAssembly Integration Guide AILANG can run entirely in the browser using WebAssembly, enabling interactive demonstrations and online playgrounds without requiring server-side execution. ## Overview The AILANG WebAssembly build provides: - **Full Language Support**: Complete AILANG interpreter compiled to WASM - **Client-Side Execution**: No server needed after initial load - **Small Bundle Size**: ~5.7MB uncompressed (~1-2MB with gzip) - **React Integration**: Ready-made component for easy integration - **Offline Capable**: Works offline after first load ## Quick Start ### 1. Build WASM Binary ```bash cd ailang make build-wasm ``` This produces `bin/ailang.wasm`. ### 2. Integration Options #### Option A: Docusaurus (Recommended) 1. Copy assets: ```bash cp bin/ailang.wasm docs/static/wasm/ # Download Go's WASM support file (more reliable than GOROOT path) curl -sL -o docs/static/wasm/wasm_exec.js \ https://raw.githubusercontent.com/golang/go/go1.22.0/misc/wasm/wasm_exec.js cp web/ailang-repl.js docs/src/components/ cp web/AilangRepl.jsx docs/src/components/ ``` 2. Add to `docusaurus.config.js`: ```javascript module.exports = { scripts: [ { src: '/wasm/wasm_exec.js', async: false, }, ], // ... rest of config }; ``` 3. Use in MDX: ```mdx --- title: Try AILANG --- import AilangRepl from '@site/src/components/AilangRepl'; ``` #### Option B: Vanilla HTML ```html AILANG REPL
``` #### Option C: React (Custom) ```jsx import { useEffect, useState } from 'react'; import AilangREPL from './ailang-repl'; export default function MyReplComponent() { const [repl, setRepl] = useState(null); const [result, setResult] = useState(''); useEffect(() => { const replInstance = new AilangREPL(); replInstance.init('/wasm/ailang.wasm').then(() => { setRepl(replInstance); }); }, []); const handleEval = (input) => { if (repl) { const output = repl.eval(input); setResult(output); } }; return (
{ if (e.key === 'Enter') handleEval(e.target.value); }} />
{result}
); } ``` ## JavaScript API ### `AilangREPL` Class ```javascript const repl = new AilangREPL(); ``` #### Methods ##### `init(wasmPath)` Initialize the WASM module. ```javascript await repl.init('/wasm/ailang.wasm'); ``` **Parameters:** - `wasmPath` (string): Path to `ailang.wasm` file **Returns:** Promise that resolves when REPL is ready ##### `eval(input)` Evaluate an AILANG expression. ```javascript const result = repl.eval('1 + 2'); // Returns: "3 :: Int" ``` **Parameters:** - `input` (string): AILANG code to evaluate **Returns:** Result string (includes value and type) ##### `command(cmd)` Execute a REPL command. ```javascript const type = repl.command(':type \x. x'); // Returns: "\x. x :: a -> a" ``` **Parameters:** - `cmd` (string): REPL command (e.g., `:type`, `:help`) **Returns:** Command output string ##### `reset()` Reset the REPL environment. ```javascript repl.reset(); ``` **Returns:** Status message ##### `onReady(callback)` Register callback for when REPL is ready. ```javascript repl.onReady(() => { console.log('REPL initialized!'); }); ``` ## REPL Commands The WebAssembly REPL supports the same commands as the CLI: | Command | Description | |---------|-------------| | `:help` | Show available commands | | `:type ` | Display expression type | | `:instances` | Show type class instances | | `:reset` | Clear environment | ## Limitations The browser version has these limitations compared to the CLI: | Feature | CLI | WASM | |---------|-----|------| | Expression evaluation | Yes | Yes | | Type inference | Yes | Yes | | Pattern matching | Yes | Yes | | Type classes | Yes | Yes | | File I/O (`FS` effect) | Yes | No | | Module imports | Yes | No | | History persistence | Yes | No | ## Deployment ### Static Hosting WASM files work on any static host: ```bash # Build and deploy make build-wasm cp bin/ailang.wasm your-site/static/wasm/ # Deploy your-site/ to Netlify/Vercel/GitHub Pages ``` ### CDN Optimization 1. **Enable Compression:** ```nginx # nginx.conf gzip_types application/wasm; ``` 2. **Set Cache Headers:** ```nginx location ~* \.wasm$ { add_header Cache-Control "public, max-age=31536000, immutable"; } ``` 3. **Use HTTP/2:** WASM benefits from HTTP/2 multiplexing for faster loading. ### Performance Tips - **Lazy Loading**: Only load WASM when user navigates to playground - **Service Worker**: Cache WASM for offline use - **CDN**: Serve from edge locations - **Preload**: Add `` ## CI/CD Integration ### GitHub Actions WASM is automatically built and released: ```yaml # .github/workflows/release.yml (excerpt) - name: Build WASM binary run: make build-wasm - name: Create Release uses: softprops/action-gh-release@v2 with: files: bin/ailang-wasm.tar.gz ``` ### Docusaurus Deployment WASM is included in documentation builds: ```yaml # .github/workflows/docusaurus-deploy.yml (excerpt) - name: Build WASM binary run: make build-wasm - name: Copy static assets run: | cp bin/ailang.wasm docs/static/wasm/ cp web/ailang-repl.js docs/src/components/ ``` ## Troubleshooting ### "WebAssembly not supported" **Solution**: Use a modern browser: - Chrome 57+ - Firefox 52+ - Safari 11+ - Edge 16+ ### "Failed to load AILANG WASM" **Solutions**: 1. Check browser console for network errors 2. Verify `ailang.wasm` path is correct 3. Ensure `wasm_exec.js` loaded first 4. Check CORS headers if serving from different domain ### "REPL not initialized" **Solution**: Wait for `init()` promise or use `onReady()`: ```javascript repl.init('/wasm/ailang.wasm').then(() => { // Safe to use repl here repl.eval('1 + 2'); }); ``` ### Slow Loading **Solutions**: 1. Enable gzip compression (reduces to ~1-2MB) 2. Use CDN 3. Add preload hints: ```html ``` ## Examples See: - [Live Playground](/docs/playground) - Try it now - [Integration Example](https://github.com/sunholo-data/ailang/blob/main/web/example.mdx) - [Component Source](https://github.com/sunholo-data/ailang/blob/main/web/AilangRepl.jsx) ## Next Steps - [Try the Playground](/docs/playground) - [Download Latest Release](https://github.com/sunholo-data/ailang/releases/latest) - [Report Issues](https://github.com/sunholo-data/ailang/issues) --- # AI Teaching Prompt (Latest: v0.5.11) # AILANG v0.5.11 - AI Teaching Prompt AILANG is a **pure functional language** with Hindley-Milner type inference and algebraic effects. Write code using **recursion** (no loops), **pattern matching**, and **explicit effect declarations**. ## Required Program Structure ```ailang module benchmark/solution import std/io (println) export func main() -> () ! {IO} { print(show(42)) -- print expects string, use show() for numbers } ``` **Rules:** 1. First line: `module benchmark/solution` 2. Use `print(show(value))` for numbers, `print(str)` for strings 3. **Inside `{ }` blocks: use `let x = e;` (semicolons). NEVER use `let x = e in`!** 4. No loops - use recursion ## CLI Exploration ```bash ailang --help # all ailang abilities ailang docs --list # List stdlib modules ailang docs std/io # Show module exports ailang builtins list # All 72 builtins ailang builtins show _ai_call # Detailed documentation ailang check file.ail # Type-check without running ``` ## Quick Reference Examples **Print calculation:** ```ailang module benchmark/solution export func main() -> () ! {IO} = print(show(5 % 3)) ``` **HTTP GET:** ```ailang module benchmark/solution import std/net (httpGet) export func main() -> () ! {IO, Net} = print(httpGet("https://example.com")) ``` **HTTP POST with JSON:** ```ailang module benchmark/solution import std/net (httpPost) import std/json (encode, jo, kv, js, jnum) export func main() -> () ! {IO, Net} { let data = encode(jo([kv("message", js("hello")), kv("count", jnum(42.0))])); print(httpPost("https://httpbin.org/post", data)) } ``` **Filter list recursively:** ```ailang module benchmark/solution export func filter(people: [{name: string, age: int}], minAge: int) -> [{name: string, age: int}] = match people { [] => [], p :: rest => if p.age >= minAge then p :: filter(rest, minAge) else filter(rest, minAge) } ``` **AI effect (call LLM):** ```ailang module benchmark/solution import std/ai (call) export func main() -> () ! {IO, AI} = print(call("What is 2+2?")) ``` ## What AILANG Does NOT Have | Invalid | Use Instead | |-----------|----------------| | `for`/`while` loops | Recursion | | `[x*2 for x in xs]` | `map(\x. x*2, xs)` or recursion | | `var`/`let mut` | Immutable `let` bindings | | `list.map()` | `map(f, list)` | | `import "std/io"` | `import std/io (println)` | | `{"key": "val"}` | `jo([kv("key", js("val"))])` | | `f(a, b)` for curried | `f(a)(b)` - curried calls chain | | mixing `let x = e in` with `;` | Use ONE style consistently | ## Let Bindings: Block Style vs Expression Style **Rule: Inside `{ }` blocks, use SEMICOLONS. With `=` bodies, use `in`.** ```ailang -- Block style: curly braces + semicolons export func main() -> () ! {IO} { let x = 1; let y = 2; print(show(x + y)) } -- Expression style: equals + in export func main() -> () ! {IO} = let x = 1 in let y = 2 in print(show(x + y)) -- WRONG: Using `in` inside `{ }` block causes scope errors export func main() -> () ! {IO} { let x = 1 in -- DON'T use `in` inside blocks! let y = 2; -- ERROR: x out of scope print(show(x + y)) } ``` **Simple rule: See `{` -> use `;`. See `=` -> use `in`.** ## Curried Functions (CRITICAL) AILANG functions are **curried**. Multi-arg lambdas must be called with chained applications: ```ailang -- Define curried function let add = \x. \y. x + y -- CORRECT: Chain calls let result = add(3)(4) -- Returns 7 -- WRONG: Don't use tuple-style let result = add(3, 4) -- ERROR: arity mismatch! ``` **Higher-order example (compose, foldl):** ```ailang module benchmark/solution export func main() -> () ! {IO} { -- WRONG: let compose = ... in (don't use "in" in { } blocks!) -- RIGHT: let compose = ...; let compose = \f. \g. \x. f(g(x)); let double = \x. x * 2; let addOne = \x. x + 1; -- WRONG: compose(addOne, double) (arity mismatch!) -- RIGHT: compose(addOne)(double) (chain curried calls) let doubleThenAdd = compose(addOne)(double); print(show(doubleThenAdd(5))) } ``` **Curried foldl (block style):** ```ailang module benchmark/solution -- Define curried foldl func foldl(f: int -> int -> int, acc: int, xs: [int]) -> int = match xs { [] => acc, x :: rest => foldl(f, f(acc)(x), rest) -- f(acc)(x) chains the curried call } export func main() -> () ! {IO} { let add = \a. \b. a + b; -- Semicolons in block! let sum = foldl(add, 0, [1,2,3,4,5]); print(show(sum)) } ``` ## Syntax Reference | Construct | Syntax | |-----------|--------| | Module | `module path/name` | | Import | `import std/io (println)` | | Import alias | `import std/list as L` | | Function | `export func name(x: int) -> int ! {IO} { body }` | | Lambda | `\x. x * 2` | | Pattern match | `match x { 0 => a, n => b }` (use `=>`, commas between arms) | | ADT | `type Tree = Leaf(int) \| Node(Tree, int, Tree)` | | Record | `{name: "A", age: 30}` | | Record update | `{base \| field: val}` | | List cons | `x :: xs` or `::(x, xs)` | | Array literal | `#[1, 2, 3]` | | Effect | `! {IO, FS, Net}` after return type | ## Effects (Side Effects Must Be Declared) Every function performing I/O must declare effects: ```ailang -- Pure (no effects) func add(x: int, y: int) -> int = x + y -- IO effect func greet(name: string) -> () ! {IO} = print("Hello " ++ name) -- Multiple effects func process(path: string) -> () ! {IO, FS} { let content = readFile(path); print(content) } ``` | Effect | Functions | Import | |--------|-----------|--------| | `IO` | `print`, `println`, `readLine` | `std/io` (print is builtin) | | `FS` | `readFile`, `writeFile` | `std/fs` | | `Net` | `httpGet`, `httpPost`, `httpRequest` | `std/net` | | `Env` | `getEnv`, `getEnvOr` | `std/env` | | `AI` | `call` | `std/ai` | | `Debug` | `log`, `check` | `std/debug` | | `SharedMem` | `_sharedmem_get`, `_sharedmem_put`, `_sharedmem_cas` | builtins | | `SharedIndex` | `_sharedindex_upsert`, `_sharedindex_find_simhash` | builtins | ## Standard Library **Auto-imported (no import needed):** - `print` (entry modules only) - `show(x)` - convert to string - Comparison operators: `<`, `>`, `<=`, `>=`, `==`, `!=` **Common imports:** ```ailang import std/io (println, readLine) import std/fs (readFile, writeFile) import std/net (httpGet, httpPost, httpRequest) import std/json (encode, decode) import std/list (map, filter, foldl, length, concat) import std/string (split, trim, stringToInt) -- stringToInt returns Option[int]! import std/ai (call) import std/sem (make_frame_at, store_frame, load_frame, update_frame) ``` ## String Parsing (Returns Option) `stringToInt` returns `Option[int]`, NOT an int. You MUST pattern match: ```ailang module benchmark/solution import std/string (stringToInt) export func main() -> () ! {IO} { match stringToInt("42") { Some(n) => print("Parsed: " ++ show(n)), None => print("Invalid number") } } ``` **With file reading (effect composition):** ```ailang module benchmark/solution import std/fs (readFile) import std/string (stringToInt) -- Pure function (no effects) pure func formatMessage(name: string, count: int) -> string = "User " ++ name ++ " has " ++ show(count) ++ " items" -- FS effect only func readCount(filename: string) -> int ! {FS} { let content = readFile(filename); match stringToInt(content) { Some(n) => n, None => 0 } } -- Combined effects: IO + FS export func main() -> () ! {IO, FS} { let count = readCount("data.txt"); let msg = formatMessage("Alice", count); print(msg) } ``` ## Operators | Type | Operators | |------|-----------| | Arithmetic | `+`, `-`, `*`, `/`, `%`, `**` | | Comparison | `<`, `>`, `<=`, `>=`, `==`, `!=` | | Logical | `&&`, `\|\|`, `!` | | String | `++` (concatenation) | | List | `::` (cons/prepend) | ## Pattern Matching ```ailang -- On lists match xs { [] => 0, x :: rest => x + sum(rest) } -- On ADTs match tree { Leaf(n) => n, Node(l, v, r) => countNodes(l) + 1 + countNodes(r) } -- On Option match result { Some(x) => x, None => defaultValue } ``` **Option type with findFirst and mapOption:** ```ailang module benchmark/solution -- Define your own Option if needed (or import std/option) type Option[a] = Some(a) | None -- Find first element matching predicate func findFirst(pred: int -> bool, xs: [int]) -> Option[int] = match xs { [] => None, x :: rest => if pred(x) then Some(x) else findFirst(pred, rest) } -- Map over Option func mapOption(f: int -> int, opt: Option[int]) -> Option[int] = match opt { Some(v) => Some(f(v)), None => None } export func main() -> () ! {IO} { -- Inside { } block: use semicolons, NOT "in" -- WRONG: let isEven = \n. n % 2 == 0 in -- RIGHT: let isEven = \n. n % 2 == 0; let isEven = \n. n % 2 == 0; let double = \x. x * 2; let nums = [1, 3, 4, 7, 8]; let found = findFirst(isEven, nums); let doubled = mapOption(double, found); print(match doubled { Some(v) => "Found: " ++ show(v), None => "Not found" }) } ``` **ADT state machine (traffic light):** ```ailang module benchmark/solution type State = Green(int) | Yellow(int) | Red(int) type Event = Tick | Reset func transition(state: State, event: Event) -> State = match event { Reset => Green(20), Tick => match state { Green(t) => if t > 1 then Green(t - 1) else Yellow(3), Yellow(t) => if t > 1 then Yellow(t - 1) else Red(10), Red(t) => if t > 1 then Red(t - 1) else Green(20) } } func showState(s: State) -> string = match s { Green(t) => "GREEN(" ++ show(t) ++ ")", Yellow(t) => "YELLOW(" ++ show(t) ++ ")", Red(t) => "RED(" ++ show(t) ++ ")" } export func main() -> () ! {IO} { -- WRONG: let s0 = Green(2) in (don't use "in" in blocks!) -- RIGHT: let s0 = Green(2); let s0 = Green(2); let s1 = transition(s0, Tick); let s2 = transition(s1, Tick); print(showState(s2)) } ``` ## JSON **Build and encode JSON:** ```ailang import std/json (encode, jo, ja, kv, js, jnum) -- Build JSON object let json = encode(jo([kv("name", js("Alice")), kv("age", jnum(30.0))])) -- Result: "{\"name\":\"Alice\",\"age\":30}" -- Build JSON array let arr = encode(ja([jnum(1.0), jnum(2.0), jnum(3.0)])) -- Result: "[1,2,3]" ``` **Decode JSON (returns Result):** ```ailang import std/json (decode, Json, JObject, JString) let result = decode("{\"name\":\"Alice\"}"); match result { Ok(json) => print(show(json)), Err(msg) => print("Parse error: " ++ msg) } ``` **Access JSON values (IMPORTANT for parsing tasks):** ```ailang import std/json (decode, get, has, getOr, asString, asNumber, asBool, asArray) import std/option (Option, Some, None) -- Decode and extract values match decode("{\"name\":\"Alice\",\"age\":30}") { Ok(obj) => { -- get(obj, key) -> Option[Json] match get(obj, "name") { Some(j) => match asString(j) { Some(name) => print("Name: " ++ name), None => print("name is not a string") }, None => print("no name field") }; -- asNumber returns Option[float] match get(obj, "age") { Some(j) => match asNumber(j) { Some(age) => print("Age: " ++ show(age)), None => print("age is not a number") }, None => print("no age field") } }, Err(msg) => print("Parse error: " ++ msg) } ``` **JSON accessor functions:** - `get(obj, key)` -> `Option[Json]` - Get value by key - `has(obj, key)` -> `bool` - Check if key exists - `getOr(obj, key, default)` -> `Json` - Get with fallback - `asString(j)` -> `Option[string]` - Extract string - `asNumber(j)` -> `Option[float]` - Extract number - `asBool(j)` -> `Option[bool]` - Extract boolean - `asArray(j)` -> `Option[List[Json]]` - Extract array - `asObject(j)` -> `Option[List[{key: string, value: Json}]]` - Extract object ## HTTP Requests **Simple GET/POST:** ```ailang import std/net (httpGet, httpPost) let body = httpGet("https://example.com") let resp = httpPost("https://api.example.com", jsonData) ``` **Advanced with headers:** ```ailang import std/net (httpRequest) let headers = [{name: "Authorization", value: "Bearer token"}]; match httpRequest("POST", url, headers, body) { Ok(resp) => print(resp.body), Err(Transport(msg)) => print("Error: " ++ msg), Err(_) => print("Other error") } ``` ## AI Effect Call external LLMs with a string->string interface: ```ailang import std/ai (call) func ask_ai(question: string) -> string ! {AI} = call(question) ``` **Run with providers:** ```bash ailang run --caps IO,AI --ai claude-haiku-4-5 --entry main file.ail # Anthropic ailang run --caps IO,AI --ai gpt5-mini --entry main file.ail # OpenAI ailang run --caps IO,AI --ai gemini-2-5-flash --entry main file.ail # Google (uses ADC) ailang run --caps IO,AI --ai-stub --entry main file.ail # Testing stub ``` ## Arrays (O(1) indexed access) ```ailang import std/array as A let arr = #[10, 20, 30] -- Array literal let val = A.get(arr, 0) -- O(1) access: 10 let safe = A.getOpt(arr, 99) -- None (out of bounds) let arr2 = A.set(arr, 0, 99) -- O(n) copy: #[99, 20, 30] ``` ## Semantic Caching Doctrine (SharedMem + SharedIndex) AILANG programs should treat `SharedMem` + `SharedIndex` as the primary persistent working memory for agents. ### When to Store Cache any expensive or repeatable computation (LLM calls, parsing, summarizing, planning, search) as a `sem_frame`: ```ailang import std/sem (make_frame_at, store_frame, load_frame) -- After expensive computation, cache it let frame = make_frame_at("plan:" ++ goal_id, plan_text, plan_bytes, timestamp); let _ = store_frame("plan:" ++ goal_id, frame) ``` ### When to Retrieve Use `SharedIndex` for meaning-based retrieval. Do NOT guess keys or enumerate all keys unless implementing maintenance tooling: ```ailang -- Find similar content by SimHash (fast, deterministic) let results = _sharedindex_find_simhash("beliefs", query_hash, 5, 100, true) -- Find by neural embedding (semantic similarity via Ollama) let query_emb = _ollama_embed("embeddinggemma", query_text); let results = _sharedindex_find_by_embedding("beliefs", query_emb, 5, 100, true) ``` ### How to Evolve State Use `update_frame` with CAS for conflict-free multi-agent updates: ```ailang import std/sem (update_frame, UpdateResult) match update_frame("plan:" ++ goal_id, \frame. refine_plan(frame)) { Updated(new_frame) => continue_with(new_frame), Conflict(current) => retry_with_backoff(current), Missing => create_initial_plan() } ``` ### How to Debug Enable tracing to see all SharedMem/SharedIndex operations: ```bash ailang run --caps IO,SharedMem,SharedIndex --trace-sharedmem --entry main file.ail ``` ### Namespace Conventions Organize frames by domain using namespace prefixes: | Prefix | Purpose | |--------|---------| | `plan:` | Planning state, goals, strategies | | `belief:` | Agent beliefs, world model | | `doc:` | Document summaries, parsed content | | `cache:` | Expensive computation results | | `session:` | Per-session temporary state | ### Two-Tier Search | Tier | Method | Use Case | Speed | |------|--------|----------|-------| | **Tier 1** | SimHash | Near-duplicates, typo tolerance | ~1ms | | **Tier 2** | Neural embedding | Semantic similarity, paraphrases | ~160ms | **Canonical pattern:** ```ailang -- Check for exact/near match first (fast) let simhash = _simhash(query_text); let near_matches = _sharedindex_find_simhash("cache", simhash, 1, 50, true); match near_matches { [] => { -- No near match: compute fresh, store result let result = expensive_computation(query_text); let frame = make_frame_at("cache:" ++ query_id, query_text, result, now()); let _ = store_frame("cache:" ++ query_id, frame); result }, [hit, ..._] => { -- Found cached result match load_frame(hit.key) { Some(frame) => frame.opaque, None => expensive_computation(query_text) -- Race: deleted between search and load } } } ``` ### Embeddings Doctrine If AI/Embedding capability is available (Ollama + EmbeddingGemma), use it to make semantic caching robust to paraphrase. **When to compute embeddings:** - Compute embeddings for frames that represent durable knowledge: document summaries, plans, policies, entity facts, extracted structured state. - Avoid embedding ephemeral "chatty" content. Prefer stable canonical text. **What to embed:** - Embed the frame's `content`, not the full `opaque` payload. - `content` should be short, canonical, and discriminative (1-3 sentences plus key identifiers/constraints). **How to retrieve (hybrid pattern):** ```ailang -- 1. SimHash candidates (fast, bounded) let hash = _simhash(query); let candidates = _sharedindex_find_simhash("beliefs", hash, 100, 1000, true); -- 2. Embed query once let qemb = _ollama_embed("embeddinggemma", query); -- 3. Rerank with embedding search let results = _sharedindex_find_by_embedding("beliefs", qemb, 5, 100, true); ``` **How to store with embeddings:** ```ailang import std/sem (make_frame_at, store_frame, with_embedding) -- Compute embedding at store time (expensive, do once) let emb_floats = _ollama_embed("embeddinggemma", content); let emb_bytes = _embedding_encode(emb_floats); let frame = with_embedding(make_frame_at(key, content, payload, ts), emb_bytes, 768); let _ = store_frame(key, frame); let _ = _sharedindex_upsert_emb("ns", key, frame.simhash, emb_floats, frame.ver, frame.ts) ``` **Debugging embeddings:** - If a decision depends on embedding rerank, record: model name, candidate set size, similarity scores, and chosen key. ### Running with SharedMem/SharedIndex ```bash # Basic SharedMem (key-value cache) ailang run --caps IO,SharedMem --entry main file.ail # Full semantic retrieval (SimHash + embeddings) ailang run --caps IO,SharedMem,SharedIndex --entry main file.ail # With Ollama embeddings (requires: ollama serve && ollama pull embeddinggemma) ailang run --caps IO,SharedMem,SharedIndex --entry main file.ail ``` ## List Operations ```ailang -- Recursive sum (no loops!) func sum(xs: [int]) -> int = match xs { [] => 0, x :: rest => x + sum(rest) } -- Recursive map func map(f: int -> int, xs: [int]) -> [int] = match xs { [] => [], x :: rest => f(x) :: map(f, rest) } ``` ## Testing **Inline tests on functions (recommended):** ```ailang -- Tests are pairs of (input, expected_output) pure func square(x: int) -> int tests [(0, 0), (5, 25)] { x * x } pure func double(x: int) -> int tests [(0, 0), (3, 6), (5, 10)] { x * 2 } ``` Run: `ailang test file.ail` ## Multi-Module Projects ``` myapp/ ├── data.ail -- module myapp/data ├── storage.ail -- module myapp/storage └── main.ail -- module myapp/main ``` ```ailang -- myapp/data.ail module myapp/data export type User = { name: string, age: int } -- myapp/main.ail module myapp/main import myapp/data (User) export func main() -> () ! {IO} = print("Hello") ``` Run: `ailang run --entry main --caps IO myapp/main.ail` ## Common Mistakes | Mistake | Fix | |---------|-----| | `print(42)` | `print(show(42))` - print needs string | | `import "std/io"` | `import std/io (println)` - no quotes | | `list.map(f)` | `map(f, list)` - standalone function | | `for x in xs` | Use recursion or `map`/`filter` | | Missing `! {IO}` | Add effect to signature | | `let x = 1; let y = 2` at top level | Wrap in `{ }` block | | `match x { ... }` inside block | Extract to helper function (parser bug) | ## Running Programs ```bash ailang run --entry main --caps IO file.ail # IO only ailang run --entry main --caps IO,FS file.ail # IO + File System ailang run --entry main --caps IO,Net file.ail # IO + Network ailang run --entry main --caps IO,AI --ai MODEL file.ail # IO + AI ailang run --entry main --caps IO,SharedMem file.ail # IO + Semantic cache ailang repl # Interactive REPL ``` **Flags must come BEFORE the filename!** --- # Examples Status ## Example Status ### Working Examples ✅ - `adt_option.ail` - `adt_simple.ail` - `ai_call.ail` ← ✨ NEW (v0.3.9) - OpenAI API integration - `arithmetic.ail` - `block_recursion.ail` ← ✨ NEW (v0.3.0-alpha2) - `claude_haiku_call.ail` ← ✨ NEW (v0.3.9) - Anthropic API integration - `demos/adt_pipeline.ail` ← ✅ FIXED (M-R5 Day 1) - `demos/hello_io.ail` - `effects_basic.ail` - `effects_pure.ail` - `guards_basic.ail` - `hello.ail` - `micro_block_if.ail` ← ✨ NEW (v0.3.0-alpha2) - `micro_block_seq.ail` ← ✨ NEW (v0.3.0-alpha2) - `micro_io_echo.ail` ← ✅ FIXED (M-R5 Day 1) - `micro_option_map.ail` ← ✅ FIXED (M-R5 Day 1) - `micro_record_person.ail` ← ✨ NEW (v0.3.0-alpha3 M-R5 Day 3) - `recursion_error.ail` - `recursion_factorial.ail` - `recursion_fibonacci.ail` - `recursion_mutual.ail` - `recursion_quicksort.ail` - `showcase/01_type_inference.ail` - `showcase/02_lambdas.ail` - `showcase/03_type_classes.ail` - `showcase/04_closures.ail` - `simple.ail` - `test_effect_annotation.ail` - `test_effect_capability.ail` - `test_effect_fs.ail` - `test_effect_io.ail` - `test_exhaustive_bool_complete.ail` - `test_exhaustive_bool_incomplete.ail` - `test_exhaustive_wildcard.ail` - `test_guard_bool.ail` - `test_guard_debug.ail` - `test_guard_false.ail` - `test_import_ctor.ail` ← ✅ FIXED (M-R5 Day 1) - `test_import_func.ail` ← ✅ FIXED (M-R5 Day 1) - `test_invocation.ail` - `test_io_builtins.ail` - `test_module_minimal.ail` - `test_no_import.ail` - `test_record_subsumption.ail` ← ✨ NEW (v0.3.0-alpha3 M-R5 Day 3) - `test_single_guard.ail` - `test_use_constructor.ail` ← ✅ FIXED (M-R5 Day 1) - `test_with_import.ail` - `type_classes_working_reference.ail` - `v3_3/imports.ail` ← ✅ FIXED (M-R5 Day 1) - `v3_3/imports_basic.ail` ← ✅ FIXED (M-R5 Day 1) ### Failing Examples ❌ - `demos/effects_pure.ail` - `experimental/ai_agent_integration.ail` - `experimental/concurrent_pipeline.ail` - `experimental/factorial.ail` - `experimental/quicksort.ail` - `experimental/web_api.ail` - `lambda_expressions.ail` - `list_patterns.ail` - `patterns.ail` - `records.ail` - `showcase/03_lists.ail` - `test_effect_io_simple.ail` - `typeclasses.ail` - `v3_3/math/gcd.ail` ### Skipped Examples ⏭️ - `block_demo.ail` - `option_demo.ail` - `stdlib_demo.ail` - `stdlib_demo_simple.ail` **Summary:** 50 passed, 14 failed, 4 skipped (Total: 68) **Recent improvements:** - ✅ **v0.3.9 (Oct 2025)**: 2 new AI API integration examples! - `ai_call.ail`: OpenAI GPT-4o-mini integration with JSON encoding - `claude_haiku_call.ail`: Anthropic Claude Haiku integration (verified with real API) - ✅ **M-R5 (v0.3.0-alpha3)**: 11 examples fixed/added via records & row polymorphism! - Day 1: 9 examples fixed (demos/adt_pipeline, micro_io_echo, micro_option_map, test_import_ctor, test_import_func, test_use_constructor, v3_3/imports, v3_3/imports_basic) - Day 3: 2 new examples (micro_record_person, test_record_subsumption) - ✅ **M-R8 (v0.3.0-alpha2)**: `micro_block_*.ail`, `block_recursion.ail` (3 files) - Block expressions with recursion - ✅ **M-R4 (v0.3.0-alpha1)**: `recursion_*.ail` (5 files) - Recursion support with RefCell indirection ---