渲染zh-Hans

failable-in-closure

Translation status: 简体中文 reader-locale proof. Term names and code fences follow the zh-Hans pack; supporting prose may still be English.

A closure is its own frame: it neither inherits the enclosing function's ⇥ channel nor leaks one; a failable call inside a closure is handled inside the closure.

Syntax: (<T>) → <R> <name> ← <params> → <R> ∴ do { do { … risky(x) … } catch err { … } }

Category#

function

Examples#

radix/corpus/clausura/failable-in-closure.fab (canonical · concept)#

A closure is its own frame: it neither inherits the enclosing function's ⇥ channel nor leaks one; a failable call inside a closure is handled inside the closure.

# =============================================================================
# failable-in-closure — closures inside failable functions, failable calls inside closures
# =============================================================================
#
# What this teaches:
#   • A closure's `return` returns a plain value of the closure, even when
#     the enclosing function declares `⇥`: the error channel belongs to the
#     function, not to the closures it creates.
#   • A failable call inside a closure body needs a handler inside that body
#     (`do { … } catch err { … }`); the handled failure becomes the closure's
#     own value, and the enclosing function never sees it.
#
# Common mistakes:
#   • Calling a failable function in a closure body with no handler and no
#     `⇥` of its own — rejected by the analyzer.
#
# See also: 闭包, ⇥, 执行, 捕获
# =============================================================================

# failable-in-closure — closures keep their own frame
#
# EXPECTED OUTPUT:
#   failable-in-closure.expected — one line per call; the handled failures print -1.

fn risky(int n) → int ⇥ string {
    if n ≻ 5 {
        throw "too big"
    }
    return n
}

# Plain closures inside a failable function: their returns are plain values.
fn plain(int n) → int ⇥ string {
    const (int) → int f ← int x → int ∴ do {
        const int y ← x + 1
        return y * 2
    }
    const (int) → int g ← int x → int ∴ x + 7
    const int z ← risky(n)
    return f(z) + g(z)
}

# A failable call nested in an argument, handled inside the closure.
fn handled(int n) → int ⇥ string {
    const (int) → int h ← int x → int ∴ do {
        var int verdict ← -1
        do {
            print "in §"(risky(x))
            verdict ← 1
        }
        catch err {
            verdict ← -1
        }
        return verdict
    }
    return h(n)
}

# The same closure in a function with no channel of its own.
fn handled_free(int n) → int {
    const (int) → int h ← int x → int ∴ do {
        var int verdict ← -1
        do {
            print "in §"(risky(x))
            verdict ← 1
        }
        catch err {
            verdict ← -1
        }
        return verdict
    }
    return h(n)
}

main {
    do {
        print plain(1)
        print plain(9)
    }
    catch err {
        print "caught: §"(err)
    }
    do {
        print handled(2)
        print handled(9)
    }
    catch err {
        print "caught: §"(err)
    }
    print handled_free(3)
    print handled_free(9)
}

Expected output:

12
caught: too big
in 2
1
-1
in 3
1
-1