# Chapter 6: Handlers

Handlers are where effects become powerful. They define *how* effect operations behave, and they can do surprising things.

## Basic Handler Structure

```lux
handler handlerName: EffectName {
    fn operation1(param1, param2) = {
        // Implementation
        resume(result)
    }
    fn operation2(param) = {
        // Implementation
        resume(result)
    }
}
```

Key points:
- Handlers implement all operations of an effect
- `resume(value)` continues the computation with `value`
- Handlers can use other effects in their implementations

## Understanding Resume

`resume` is the key to handler power. It continues the computation from where the effect was called.

```lux
effect Ask {
    fn ask(prompt: String): Int
}

fn computation(): Int with {Ask} = {
    let x = Ask.ask("first")   // Pauses here
    let y = Ask.ask("second")  // Then here
    x + y
}

handler doubler: Ask {
    fn ask(prompt) = resume(2)  // Always returns 2
}

run computation() with { Ask = doubler }
// Returns: 4 (2 + 2)
```

The flow:
1. `computation` calls `Ask.ask("first")`
2. Handler receives control, calls `resume(2)`
3. `computation` continues with `x = 2`
4. `computation` calls `Ask.ask("second")`
5. Handler receives control, calls `resume(2)`
6. `computation` continues with `y = 2`
7. Returns `4`

## Handlers That Don't Resume

Not all handlers must resume. Some can abort:

```lux
effect Validate {
    fn check(condition: Bool, message: String): Unit
}

fn validateAge(age: Int): String with {Validate} = {
    Validate.check(age >= 0, "Age cannot be negative")
    Validate.check(age < 150, "Age seems unrealistic")
    "Valid age: " + toString(age)
}

handler strictValidator: Validate {
    fn check(cond, msg) =
        if cond then resume(())
        else "Validation failed: " + msg  // Returns early, doesn't resume
}

run validateAge(-5) with { Validate = strictValidator }
// Returns: "Validation failed: Age cannot be negative"
```

## Handlers Using Other Effects

Handlers can use effects in their implementation:

```lux
effect Logger {
    fn log(msg: String): Unit
}

handler consoleLogger: Logger {
    fn log(msg) = {
        Console.print("[LOG] " + msg)  // Uses Console effect
        resume(())
    }
}

fn main(): Unit with {Console} = {
    let result = run {
        Logger.log("Hello")
        Logger.log("World")
        42
    } with { Logger = consoleLogger }
    Console.print("Result: " + toString(result))
}
```

## Stateful Handlers

Handlers can maintain state using the State effect:

```lux
effect Counter {
    fn increment(): Unit
    fn get(): Int
}

handler counterHandler: Counter {
    fn increment() = {
        State.put(State.get() + 1)
        resume(())
    }
    fn get() = resume(State.get())
}

fn counting(): Int with {Counter} = {
    Counter.increment()
    Counter.increment()
    Counter.increment()
    Counter.get()
}

fn main(): Unit with {Console} = {
    let result = run {
        run counting() with { Counter = counterHandler }
    } with { State = 0 }
    Console.print("Count: " + toString(result))  // Count: 3
}
```

## Handler Patterns

### The Reader Pattern

Provide read-only context:

```lux
effect Config {
    fn get(key: String): String
}

handler envConfig: Config {
    fn get(key) = resume(Process.env(key))
}

handler mapConfig(settings: Map<String, String>): Config {
    fn get(key) = resume(Map.getOrDefault(settings, key, ""))
}
```

### The Writer Pattern

Accumulate output:

```lux
effect Log {
    fn write(msg: String): Unit
}

handler collectLogs: Log {
    fn write(msg) = {
        State.put(State.get() + msg + "\n")
        resume(())
    }
}

fn program(): Int with {Log} = {
    Log.write("Starting")
    let result = 42
    Log.write("Done")
    result
}

// Get both result and logs
let (result, logs) = run {
    run program() with { Log = collectLogs }
    let logs = State.get()
    (result, logs)
} with { State = "" }
```

### The Exception Pattern

Early termination with cleanup:

```lux
effect Fail {
    fn fail(msg: String): Unit
}

handler catchFail: Fail {
    fn fail(msg) = Err(msg)  // Don't resume, return error
}

fn riskyOperation(): Int with {Fail} = {
    if Random.bool() then Fail.fail("Bad luck!")
    else 42
}

let result: Result<Int, String> = run riskyOperation() with { Fail = catchFail }
```

### The Choice Pattern

Non-determinism:

```lux
effect Choice {
    fn choose(options: List<T>): T
}

fn picker(): Int with {Choice} = {
    let x = Choice.choose([1, 2, 3])
    let y = Choice.choose([10, 20])
    x + y
}

// Handler that returns first option
handler firstChoice: Choice {
    fn choose(opts) = resume(List.head(opts))
}

// Handler that returns all combinations
handler allChoices: Choice {
    fn choose(opts) =
        List.flatMap(opts, fn(opt: T): List<T> => resume(opt))
}
```

## Combining Multiple Handlers

Multiple effects, multiple handlers:

```lux
effect Logger { fn log(msg: String): Unit }
effect Counter { fn count(): Int }

fn program(): Int with {Logger, Counter} = {
    Logger.log("Starting")
    let n = Counter.count()
    Logger.log("Got " + toString(n))
    n * 2
}

handler myLogger: Logger {
    fn log(msg) = { Console.print(msg); resume(()) }
}

handler myCounter: Counter {
    fn count() = resume(42)
}

let result = run program() with {
    Logger = myLogger,
    Counter = myCounter
}
```

## Handler Scope

Handlers apply to their `run` block:

```lux
handler loudLogger: Logger {
    fn log(msg) = { Console.print("!!! " + msg + " !!!"); resume(()) }
}

handler quietLogger: Logger {
    fn log(msg) = resume(())  // Silent
}

fn program(): Unit with {Logger, Console} = {
    Logger.log("Outer")

    let inner = run {
        Logger.log("Inner")
        42
    } with { Logger = quietLogger }

    Logger.log("Back to outer")
    Console.print("Inner result: " + toString(inner))
}

run program() with { Logger = loudLogger }
// Output:
// !!! Outer !!!
// !!! Back to outer !!!
// Inner result: 42
```

The inner `run` uses `quietLogger`, so "Inner" is silent.

## Real-World Example: Database Testing

```lux
effect Database {
    fn query(sql: String): List<Row>
    fn execute(sql: String): Int
}

// Production handler using real database
handler postgresDb(conn: Connection): Database {
    fn query(sql) = resume(Postgres.query(conn, sql))
    fn execute(sql) = resume(Postgres.execute(conn, sql))
}

// Test handler using in-memory data
handler mockDb(data: List<Row>): Database {
    fn query(sql) = resume(data)
    fn execute(sql) = resume(1)
}

fn getUserCount(): Int with {Database} = {
    let rows = Database.query("SELECT COUNT(*) FROM users")
    extractCount(rows)
}

// Production
run getUserCount() with { Database = postgresDb(realConnection) }

// Testing - no database needed!
run getUserCount() with { Database = mockDb([Row { count: 42 }]) }
```

## Summary

| Pattern | Use Case | Resume? |
|---------|----------|---------|
| Basic | Provide implementation | Yes |
| Early return | Validation, errors | No |
| Reader | Configuration | Yes |
| Writer | Logging, accumulation | Yes |
| State | Counters, caches | Yes |
| Exception | Error handling | Sometimes |

## Next

[Chapter 7: Modules](07-modules.md) - Organizing code across files.
