Getting Started Series

Follow these tutorials in order to build a solid foundation in Simplex, from basic syntax to building complete AI-powered applications.

Start from the Beginning

New to Simplex? Start with Tutorial 1: Hello World and work through each tutorial in order. Each builds on concepts from the previous one.

Quick Tutorials

Variables and Types

Simplex uses let for immutable bindings and var for mutable ones:

variables.sx
// Immutable - preferred default
let name = "Simplex"        // Type inferred as String
let version: i64 = 1       // Explicit type annotation

// Mutable - when you need to change values
var count = 0
count += 1                    // OK: count is mutable

// Basic types
let integer: i64 = 42
let float: f64 = 3.14
let boolean: Bool = true
let text: String = "Hello"

// Collections
let list = [1, 2, 3]                    // List<i64>
let map = {"key": "value"}             // Map<String, String>
let tuple = (1, "two", 3.0)             // (i64, String, f64)

Functions

Functions are defined with fn. Return types are inferred or explicit:

functions.sx
// Basic function
fn greet(name: String) -> String {
    "Hello, {name}!"   // Last expression is returned
}

// Generic function
fn first<T>(items: List<T>) -> Option<T> {
    if items.is_empty() {
        None
    } else {
        Some(items[0])
    }
}

// Closures
let double = x => x * 2
let numbers = [1, 2, 3].map(x => x * 2)  // [2, 4, 6]

// Higher-order functions
fn apply_twice(f: fn(i64) -> i64, x: i64) -> i64 {
    f(f(x))
}

let result = apply_twice(double, 5)  // 20

Pattern Matching

Pattern matching is powerful and expressive in Simplex:

patterns.sx
// Match on enums
enum Shape {
    Circle(radius: f64),
    Rectangle(width: f64, height: f64),
    Triangle(base: f64, height: f64)
}

fn area(shape: Shape) -> f64 {
    match shape {
        Shape::Circle(r) => 3.14159 * r * r,
        Shape::Rectangle(w, h) => w * h,
        Shape::Triangle(b, h) => 0.5 * b * h
    }
}

// Match with guards
fn describe(n: i64) -> String {
    match n {
        0 => "zero",
        n if n < 0 => "negative",
        n if n > 100 => "large",
        _ => "positive"
    }
}

// Destructuring
let (x, y) = get_point()
let User { name, email, .. } = get_user()

Actors

Actors are the core concurrency primitive in Simplex:

actors.sx
actor BankAccount {
    var balance: f64 = 0.0

    // Fire-and-forget message
    receive Deposit(amount: f64) {
        balance += amount
        checkpoint()  // Persist state
    }

    // Request-response message
    receive Withdraw(amount: f64) -> Result<f64, Error> {
        if amount > balance {
            return Err(Error("Insufficient funds"))
        }
        balance -= amount
        checkpoint()
        Ok(balance)
    }

    receive GetBalance -> f64 {
        balance
    }
}

// Using the actor
fn main() {
    let account = spawn BankAccount

    send(account, Deposit(100.0))        // Fire-and-forget

    let balance = ask(account, GetBalance) // Request-response
    print("Balance: {balance}")
}

AI Integration

AI operations are first-class citizens in Simplex:

ai-integration.sx
fn process_document(doc: String) {
    // Text completion
    let summary = await ai::complete(
        "Summarize this document: {doc}"
    )

    // Generate embedding
    let embedding = ai::embed(doc)

    // Structured extraction
    struct Metadata {
        title: String,
        author: Option<String>,
        date: Option<Date>,
        topics: List<String>
    }

    let metadata = await ai::extract<Metadata>(doc)

    // Classification
    enum Category { Technical, Business, Legal, Personal }
    let category = await ai::classify<Category>(doc)

    // Parallel AI operations
    let (sum, ents, sent) = await parallel(
        ai::complete("Summarize: {doc}"),
        ai::extract<List<Entity>>("Extract entities: {doc}"),
        ai::classify<Sentiment>(doc)
    )
}

Next Steps