=> |
August 25, 2026 · View on GitHub
One file with everything needed to write correct Culebra: the syntax,
the habits from other languages that do not carry over, and every
standard-library signature. The reference set it condenses
(handbook.md, language.md,
stdlib.md) is around 150k tokens; this is the part that
fits in a prompt.
Every ```culebra block below is executed by culebra test --doc docs, so it cannot drift from the implementation. A line ending in
# => <value> is verified stdout; # !! <pattern> is a verified
throw. Section 4 is generated from the reference docs by just gen-quick-guide — do not edit it by hand.
Contents
1. Running a program
culebra prog.cul # the bytecode VM (default)
culebra --jit prog.cul # LLVM ORC JIT — identical output
culebra build prog.cul -o prog # AOT, self-contained binary
culebra test # run every test_*.cul below the cwd
culebra fmt -i . # format in place (no style options)
culebra lint . # static checks; exit 1 warn, 2 error
culebra docs -g 'Math.wrap' # look a signature up in the reference
Source files use the .cul extension. There is no project file, no
manifest, and no package manager: everything in section 4 is in scope
without an import.
Undefined names are rejected before the program runs, so a wrong library guess fails immediately rather than halfway through:
# !! undefined variable 'puts'
puts('hi')
That check covers names, not members: Math.abss(1) and xs.len()
survive lint and fail when the line runs, and a missing property is
nil rather than an error. So run what you write — a program that has
only been linted has not been checked.
The whole reference set is inside the binary, always matching the build
being run. culebra docs -g <pattern> prints the sections that match
and exits 1 when none do, which settles whether an API exists without
reading the output. Patterns are identifiers or phrases, not questions.
2. Syntax
2.1 Bindings
Bindings are immutable unless declared mut. A bare x = ...
introduces a binding, or reassigns the nearest enclosing one.
x = 1 # immutable binding, or reassign an outer one
let y = 2 # immutable; must not shadow an outer binding
mut z = 3 # mutable
z = 4 # bare reassignment
z += 1 # also -= *= /= %= **= @=
inspect(z) # => 5
Parameters are immutable too — assigning to one is an error, not a local copy:
bump = fn (n) {
n += 1
n
}
inspect(try {
bump(1)
} catch e {
e.kind
}) # => 'ImmutableError'
Introducing a binding that would shadow a captured outer variable is a compile-time error. Block-local rebinding inside one function is fine.
2.2 Types
inspect(type_of(nil)) # => 'Nil'
inspect(type_of(true)) # => 'Bool'
inspect(type_of(42)) # => 'Long'
inspect(type_of(3.14)) # => 'Float'
inspect(type_of('hi')) # => 'String'
inspect(type_of([1, 2])) # => 'Array'
inspect(type_of({a: 1})) # => 'Object'
inspect(type_of(fn () {
1
})) # => 'Function'
inspect(type_of((1, 'a'))) # => 'Tuple'
inspect(type_of({1, 2})) # => 'Set'
inspect(type_of('hello'.slice(1, 3))) # => 'StringView'
Tensor is the twelfth (section 4). Object is the substrate for
classes, modules and errors.
2.3 Control flow
if, match and cond are expressions; while and for are
statements.
n = 7
sign = if n > 0 {
1
} else if n < 0 {
-1
} else {
0
}
inspect(sign) # => 1
label = match n {
0 => 'zero',
k if k < 10 => 'small',
_ => 'large',
}
inspect(label) # => 'small'
grade = cond {
# a subjectless match
n >= 90 => 'A',
n >= 5 => 'B',
_ => 'C',
}
inspect(grade) # => 'B'
inspect(n > 5 ? 'big' : 'small') # => 'big'
for i in 0..3 {
inspect(i)
} # exclusive; 0..=2 inclusive; `by k` steps
# => |
# 0
# 1
# 2
for k, v in {a: 1, b: 2} {
inspect("{k}={v}")
}
# => |
# 'a=1'
# 'b=2'
break and continue work in both loops. A nobreak block runs only
if the loop was not broken out of. while, if and match accept an
init clause scoped to the construct:
for v in [1, 3, 5] {
if v % 2 == 0 {
break
}
} nobreak {
inspect('all odd') # => 'all odd'
}
while mut i = 0; i < 3 {
i += 1
}
if let m = 6; m > 5 {
inspect('big')
} # => 'big'
2.4 Functions
add = fn (a, b) {
a + b
}
inspect(add(2, 3)) # => 5
typed = fn (a: Long, b: Long) -> Long {
a + b
}
inspect(typed(2, 3)) # => 5
square = |x| x * x # a lambda body is a single expression
inspect(square(7)) # => 49
inspect([1, 2, 3].map(|x| x * 2)) # => [2, 4, 6]
inspect([[1, 2]].map(fn ((a, b)) {
a + b
})) # => [3]
Bind a literal like any other value (name = fn (...) { ... }), or use
the declaration form fn name(...) { ... }. Pass a callback inline as
|x|; a lambda body is a single expression, so switch to
fn (x) { ... } when the callback needs statements.
For a named function — one you are going to call by name, especially a
recursive one — prefer the declaration form. Only it can be a
generator or take part in multimethod
dispatch, and only it gives
fn.name a source-level name; the two forms are otherwise
interchangeable, and inside either one a bare fn in the body calls
the function itself:
fn fib(x) {
if x < 2 {
x
} else {
fn(x - 2) + fn(x - 1)
}
}
inspect(fib(10)) # => 55
inspect(fib.name) # => 'fib'
A block evaluates to its last expression, so return is rarely
needed. * makes the rest keyword-only, **rest collects unknown
keywords, *rest collects extra positionals:
greet = fn (name, *, greeting = 'hi', **opts) {
suffix = opts.has('loud') && opts.loud ? '!' : ''
"{greeting}, {name}{suffix}"
}
inspect(greet('alice')) # => 'hi, alice'
inspect(greet('bob', greeting: 'yo')) # => 'yo, bob'
inspect(greet('cy', loud: true)) # => 'hi, cy!'
inspect(greet('dee', **{greeting: 'hey'})) # => 'hey, dee'
2.5 Strings
Double quotes interpolate; single quotes are literal.
name = 'Culebra'
inspect("hello, {name}") # => 'hello, Culebra'
inspect('hello, {name}') # => 'hello, {name}'
inspect('a' + 'b') # => 'ab'
size() counts UTF-8 bytes; for and iter() step one Unicode
scalar; graphemes() steps one user-perceived character. There is no
s[i] operator — use slice, which takes byte offsets.
inspect('café'.size()) # => 5
inspect('café'.graphemes().collect().size()) # => 4
inspect('café'.slice(0, 1)) # => 'c'
inspect('hello world'.split(' ')) # => ['hello', 'world']
inspect(['a', 'b'].join('-')) # => 'a-b'
""" is a block string: it interpolates like "...", strips the
indentation of its closing delimiter, and drops the newline before it.
The closing """ must be on its own line. Use it for anything
multi-line rather than concatenating \n.
sql = """
SELECT *
FROM t
"""
inspect(sql.lines()) # => ['SELECT *', 'FROM t']
2.6 Iterators
range is lazy, iota allocates. .iter() makes an Array lazy;
chains stop at the first consumer and build no intermediates.
inspect(iota(3)) # => [0, 1, 2]
inspect(range(1000).filter(|x| x % 2 == 0).map(|x| x * 3).take(4).collect())
# => [0, 6, 12, 18]
inspect(range(1, 11).reduce(0, |a, x| a + x)) # => 55
inspect([1, 2, 3, 4].iter().zip(['a', 'b']).collect().size()) # => 2
for i, v in ['x', 'y'].enumerate() {
inspect("{i}:{v}")
}
# => |
# '0:x'
# '1:y'
A fn whose body contains yield is a generator; calling it returns
an iterator.
fn countdown(start) {
mut i = start
while i > 0 {
yield i
i -= 1
}
}
inspect(countdown(3).collect()) # => [3, 2, 1]
Any object with iter(), has_next() and next() works with for
and with every chain method.
2.7 Pattern matching
describe = fn (v) {
match v {
0 => 'zero',
1 | 2 | 3 => 'small',
n: Long if n > 100 => "big ({n})",
n: Long => "int ({n})",
s: String => "str ({s})",
[] => 'empty',
[x] => "one ({x})",
[head, ...tail] => "head={head} rest={tail.size()}",
{name} => "named {name}",
_ => 'other',
}
}
inspect(describe(2)) # => 'small'
inspect(describe(999)) # => 'big (999)'
inspect(describe([1, 2, 3])) # => 'head=1 rest=2'
inspect(describe({name: 'z'})) # => 'named z'
There is no exhaustiveness check; supply a _ arm.
2.8 Errors, defer, drop
Any value can be thrown, and try is an expression.
check = fn (x) {
if x < 0 {
throw "negative: {x}"
}
x
}
inspect(try {
check(-1)
} catch e {
e
}) # => 'negative: -1'
inspect(try {
check(7)
} catch _ {
0
}) # => 7
Built-in errors are Objects carrying a kind:
inspect(try {
1 / 0
} catch e {
e.kind
}) # => 'ZeroDivisionError'
defer runs on every exit path from the enclosing block, in LIFO
order. An Object with a no-arg drop property has it called when the
last reference goes away.
{
defer {
inspect('second')
}
defer {
inspect('first')
}
inspect('body')
}
# => |
# 'body'
# 'first'
# 'second'
{
r = {drop: fn () {
inspect('released')
}}
inspect('in scope')
}
inspect('after')
# => |
# 'in scope'
# 'released'
# 'after'
2.9 Classes, UFCS, multimethods, traits
Fields are reached through self (not this). Calling the class is
shorthand for .new.
class Car {
wheels = 4 # declared field with a default
new(mpr) {
self.miles = 0
self.mpr = mpr
}
run(n) {
self.miles += self.mpr * n
}
get far() {
self.miles > 10
} # computed property, no parentheses
static unit() {
Car(1)
}
}
c = Car(5)
c.run(3)
inspect(c.miles) # => 15
inspect(c.far) # => true
inspect(c.wheels) # => 4
inspect(c.class) # => 'Car'
Operators map to dunder methods (__add__, __eq__, __lt__,
__index__, __setindex__, __call__, ...). Reverse-side methods
(__radd__) do not exist — put the overload on the type that owns the
operation.
Any free function f(x, ...) can be called as x.f(...), but an
existing property or method always wins:
double = fn (x) {
x * 2
}
inspect(42.double()) # => 84
Several free functions may share a name and dispatch on their declared parameter types:
class Circle {
new(r) {
self.r = r
}
}
fn area(c: Circle) {
3 * c.r * c.r
}
fn area(n: Long) {
n
}
inspect(area(Circle(2))) # => 12
inspect(area(10)) # => 10
A trait is structural: any class with matching method names and
arities conforms, with no impl declaration. Trait methods may carry
a default body, and @derive(Eq, Hash, Show, Comparable) generates
the usual conformance methods.
trait Greeter {
hello() -> String
}
class Bob {
new(n) {
self.n = n
}
hello() {
"hi, {self.n}"
}
}
greet = fn (g: Greeter) -> String {
g.hello()
}
inspect(greet(Bob('Ann'))) # => 'hi, Ann'
2.10 Effects
perform invokes an operation whose meaning the enclosing handle
decides. A continuation is multi-shot.
effect fn ask()
inspect(handle {
perform ask() * 2
} with ask(resume) {
resume(21)
}) # => 42
A clause that never calls resume discards the rest of the
computation — that is exactly an exception. with return(v) { ... }
maps the normal-completion value.
2.11 Modules
export and import are top-level only, so the dependency graph is
known at parse time.
# doctest: skip
# lib.cul
let greet = fn (n) {
"hello, {n}"
}
export {greet}
# doctest: skip
# main.cul
import lib from './lib.cul'
inspect(lib.greet('world')) # => 'hello, world'
The path is a single-quoted literal resolved relative to the importing
file. Each module is evaluated once; a cycle is an ImportError.
2.12 Optional type annotations
Annotations are checked at three boundaries — assignment, parameter
passing, and return — and nowhere else. Long | String is a union,
T? is T | Nil, and Array<Long> documents the element type
without checking it elementwise.
show = fn (x: Long | String) -> String {
to_string(x)
}
inspect(show(1)) # => '1'
inspect(show('hi')) # => 'hi'
3. What does not carry over
Each row is a habit from another language that fails, or silently produces something else, in Culebra.
| Reaching for | Culebra |
|---|---|
'text {x}' interpolating | only "..." interpolates; '...' is literal |
puts / console.log / print(x) adding a newline | inspect(x) quoted debug form, println(x) raw + newline, print(x) raw |
this | self |
x |> f() | UFCS: x.f(). There is no pipeline operator |
{3} as a one-element Set | SyntaxError. One element is {3,}; {} is the empty Object |
a | b, a & b on sets | methods: a.union(b), a.intersect(b), a.diff(b) |
{a: 1} + {b: 2} | TypeError. There is no Object merge operator |
s[0] on a String | TypeError. Use s.slice(0, 1), which takes byte offsets |
-7 % 3 == 2 (Python) | -1 — the sign follows the dividend, as in C |
-7 / 2 == -4 (Python) | -3 — Long division truncates toward zero |
if [] { }, if '' { } | TypeError. Only Bool, Long and Float are testable |
0 == false | false — there is no cross-type coercion |
.length / .count | .size(). A missing property is nil, so .length reads as nil instead of raising |
.append(x) | .push(x) |
del a[i] / a.splice(i, 1) | a.remove_at(i), which returns the removed element |
obj['missing'] | KeyError. obj.missing is nil; obj.get('missing', dflt) takes a fallback |
'ab' * 3 | TypeError. There is no string repetition operator |
s.find(x) / s.indexOf(x) | s.index_of(x) — a byte offset, -1 when absent |
s.ljust(10) / s.padStart(10) / s.zfill(5) | the interpolation format spec: "{s:<10}", "{n:05}" |
s.split() with no argument, splitting on whitespace | s.split_whitespace(). split always takes a separator |
| assigning to a parameter | parameters are immutable — ImmutableError |
x = 1 twice in one scope | ImmutableError. Declare mut x = 1 |
and / or / not | && / || / ! |
elif | else if |
# only, or // only, for comments | both work, plus /* ... */ |
async / await | absent by design — I/O blocks; use Isolate / Parallel |
| a package manager | everything in section 4 is in scope with no import |
Two that yield a value rather than an error, and so are easy to miss:
# split returns StringView, not String — cheap, but type_of differs
inspect(type_of('a,b'.split(',')[0])) # => 'StringView'
# a missing property is nil, silently
inspect([1, 2].length) # => nil
inspect([1, 2].size()) # => 2
Idioms
The rows above fail loudly. These ones run — they are just not how the language is written, and nothing will tell you so. Prefer the right column.
Porting from another language: its if/elif/else or case/switch
chains map onto match/cond here, not onto a literal if/else if
chain — carrying the source's control-flow shape over verbatim is the
single most common transfer mistake.
| Works, but | Write |
|---|---|
if c { a } else { b } as a value | c ? a : b |
if / else if chain yielding a value | one value against constants: match; unrelated conditions: cond |
"a" + x + "b" (splicing literal text around a value) | "a{x}b" |
i = i + 1 | i += 1 |
x.size() == 0 / > 0 | x.empty() / !x.empty() |
mut i = 0 alongside a loop, i += 1 | for i, v in xs.enumerate() |
mut out = [] + for + out.push(f(x)) | xs.map(f) — same for filter |
mut t = {} + for + t[k] = v | xs.map(|x| (k(x), v(x))).to_object() |
mut found = false + while !found | for x in xs { … break }, or xs.find(p) |
mut hit = false + for + if p(x) { hit = true; break } | xs.any(p) (xs.all(p) for the inverse) |
"a\n" + "b\n" | a """ block |
.map(fn (x) { expr }) | .map(|x| expr) |
range(0, n) | range(n) |
iota(n).map(|_| v) | repeat(n, v) |
for i in 0..xs.size() { xs[i] … } | for x in xs |
mut i = start; while i < end { …; i += 1 } | for i in start..end { … } |
{k1: v1, k2: obj.k2, k3: obj.k3} (copy every field to change one) | {...obj, k1: v1} |
if cond { stmt } — single statement, no else | stmt if cond (stmt unless cond for the negation) |
if x == nil { x = v } / if !d.has(k) { d[k] = v } | x ??= v / d[k] ??= v — also targets obj.key |
"{a.b(c).d ?? e}" — a long/nested expression inline | let x = a.b(c).d ?? e, then "{x}" |
cond is a match with no subject, so a chain of unrelated tests is
cond { a > 1 => …, b < 2 => …, _ => … }. A loop that must report
whether it finished takes a nobreak block instead of a flag.
4. Signature index
Receivers are named by convention: s a String, a an Array, o an
Object, it an Iterator, re a compiled Regex, f an open File. An
entry with no receiver at all (contains(x) under Set methods,
json() under Http) is a method on that group's own type.
String methods — s.size() -> Long; s.empty() -> Bool; s.presence() -> String | StringView | Nil; s.upper() -> String; s.lower() -> String; s.capitalize() -> String; s.title() -> String; s.normalize(form: StringLike = "NFC") -> String; s.eq_ignore_case(other: StringLike) -> Bool; s.reverse() -> String; s.repeat(n: Long) -> String; s.truncate(max: Long, ellipsis: StringLike = "...") -> String; s.trim() -> String; s.trim_start(chars: StringLike = "") -> String; s.trim_end(chars: StringLike = "") -> String; s.tr(from: StringLike, to: StringLike) -> String; s.split(sep: StringLike, limit: Long = 0) -> Array
Array methods — a.size() -> Long; a.empty() -> Bool; a.presence() -> Array | Nil; a.push(x: Any) -> Nil (mutating); a.pop() -> Any (mutating); a.extend(other: Array) -> Nil (mutating); a.insert(i: Long, x: Any) -> Nil (mutating); a.remove_at(i: Long) -> Any (mutating); a.get(i: Long, fallback: Any) -> Any; a.slice(start: Long, end: Long) -> Array; a.join(sep: String) -> String; a.contains(v: Any) -> Bool; a.index_of(v: Any) -> Long; a.reverse() -> Nil (mutating); a.map(f: Function) -> Array; a.filter(f: Function) -> Array; a.for_each(f: Function) -> Nil; a.reduce(init: Any, f: Function) -> Any; a.find(f: Function) -> Any; a.any(f: Function) -> Bool; a.all(f: Function) -> Bool; a.flat_map(f: Function) -> Array; a.sum() -> Long | Float; a.product() -> Long | Float; a.min() -> Any; a.max() -> Any; a.min_by(f: Function) -> Any; a.max_by(f: Function) -> Any; a.to_set() -> Set; a.to_object() -> Object; a.group_by(f: Function) -> Object; a.partition(p: Function) -> Tuple; a.unzip() -> Tuple; a.sort(reverse: Bool = false) -> Nil (mutating); a.sorted(reverse: Bool = false) -> Array; a.sort_by(key: Function, reverse: Bool = false) -> Nil (mutating); a.sorted_by(key: Function, reverse: Bool = false) -> Array
Object methods — o.size() -> Long; o.empty() -> Bool; o.presence() -> Object | Nil; o.keys() -> Array; o.values() -> Iterator; o.has(key: String) -> Bool; o.get(key, fallback) -> value; o.get_or_put(key, init) -> value (mutating); o.remove(key: String) -> Nil (mutating)
Set methods — size(); empty() -> Bool; presence(); contains(x) -> Bool; union(b); intersect(b); diff(b); sym_diff(b); subset(b) -> Bool; superset(b) -> Bool; to_array(); iter(); add(x); remove(x)
Iterator methods — it.map(f); it.filter(p); it.take(n); it.skip(n); it.take_while(p); it.skip_while(p); it.step_by(n); it.distinct(); it.tap(f); it.scan(init, f); it.flatten(); it.chunk_by(f); it.chunks(n); it.windows(n); it.flat_map(f); it.chain(other); it.zip(other); it.enumerate(); it.collect(); it.join(sep); it.for_each(f); it.reduce(init, f); it.find(p); it.any(p); it.all(p); it.count(); it.first(); it.last(); it.nth(n); it.position(p); it.contains(v); it.sum(); it.product(); it.min(); it.max(); it.min_by(f); it.max_by(f); it.to_set(); it.to_object(); it.group_by(f); it.partition(p); it.unzip()
Core built-ins — to_long(v: Any, *, base: Long = 10) -> Long; to_float(v: Any) -> Float; to_string(v: Any) -> String; type_of(v: Any) -> String; range(n: Long, *, step: Long = 1) -> Iterator; range(start: Long, end: Long, *, step: Long = 1) -> Iterator; iota(n: Long) -> Array; iota(start: Long, end: Long) -> Array; repeat(n: Long, value: Any) -> Array; grid(x_range: Range, y_range: Range) -> Iterator
Math — Math.pi; Math.e; Math.inf; Math.nan; Math.abs(x: Long|Float) -> Long|Float; Math.min(a, b, ...) -> Long|Float; Math.max(a, b, ...) -> Long|Float; Math.log(x: Long|Float) -> Float; Math.exp(x: Long|Float) -> Float; Math.sqrt(x: Long|Float) -> Float; Math.sin(x) -> Float; Math.cos(x) -> Float; Math.tan(x) -> Float; Math.asin(x) -> Float; Math.acos(x) -> Float; Math.atan(x) -> Float; Math.atan2(y, x) -> Float; Math.floor(x: Long|Float) -> Long; Math.ceil(x: Long|Float) -> Long; Math.round(x: Long|Float) -> Long; Math.pow(base: Long, exp: Long) -> Long; Math.sign(x: Long) -> Long; Math.clamp(x: Long|Float, lo: Long|Float, hi: Long|Float) -> Long|Float; Math.wrap(x: Long, n: Long) -> Long
IO — IO.inspect(x: Any) -> Nil; IO.print(x: Any) -> Nil; IO.println(x: Any = '') -> Nil; IO.input() -> String; IO.stdin() -> reader; .read(); .read(n: Long); .lines(); IO.einspect(x: Any) -> Nil; IO.eprint(x: Any) -> Nil; IO.eprintln(x: Any) -> Nil; IO.stdin_is_terminal() -> Bool; IO.stdout_is_terminal() -> Bool; IO.stderr_is_terminal() -> Bool
FS — FS.join(parts...: String) -> String; FS.basename(path: String) -> String; FS.dirname(path: String) -> String; FS.extension(path: String) -> String; FS.stem(path: String) -> String; FS.read(path: String) -> String; FS.write(path: String, content: String) -> Nil; FS.exists(path: String) -> Bool; FS.is_file(path: String) -> Bool; FS.is_dir(path: String) -> Bool; FS.size(path: String) -> Long; FS.list_dir(path: String) -> Array
File — File.open(path: String, mode: String = "r") -> File; File.with(path: String, mode: String = "r", fn: Function) -> Any; f.read() -> String; f.read(n: Long) -> String; f.lines() -> Iterator
Time — Time.now() -> Instant; Time.monotonic() -> Float; Time.sleep(secs: Float) -> Nil; Time.from_iso(s: String) -> Instant; Time.from_unix(secs: Long|Float) -> Instant; Time.from_parts(p: Object, utc: false) -> Instant; Time.parse(s: String, fmt: String) -> Instant; t.iso(utc: true) -> String; t.format(fmt: String, utc: false) -> String; t.parts(utc: false) -> Object; t.weekday(utc: false) -> Long; t.add(years=0, months=0, days=0, hours=0, minutes=0, seconds=0, utc: false) -> Instant; t.start_of(unit: String, utc: false) -> Instant; t.unix() -> Float; t.unix_nanos() -> Long; d.seconds() / .milliseconds() / .minutes() / .hours() / .days() -> Float; d.abs() -> Duration
Random — Random.seed(n: Long) -> Nil; Random.int(lo: Long, hi: Long) -> Long; Random.uniform(lo: Float, hi: Float) -> Float; Random.gauss(mu: Float, sigma: Float) -> Float; Random.shuffle(a: Array) -> Nil; Random.weighted_choice(pop: Array, weights: Array) -> Any; Random.choice(pop: Array) -> Any
Sys — Sys.exit(code: Long) -> Nil; Sys.env(name: String, fallback = '') -> Any; Sys.set_env(name: String, value: String) -> Nil; Sys.getcwd() -> String; Sys.chdir(path: String) -> Nil; Sys.data_dir(app: String) -> String; Sys.time() -> Float
Tensor — Tensor.zeros(...) -> Tensor; Tensor.ones(...); Tensor.randn(...); Tensor.from(arr: Array) -> Tensor; Tensor.concat(parts: Array) -> Tensor; Tensor.from_csv(path: String) -> Tensor; Tensor.eval(t1, t2, ...) -> Nil; .shape() -> Array; .dot(other: Tensor) -> Tensor; .linear_sigmoid(x, b) -> Tensor; .pow(exp) -> Tensor; .transpose() -> Tensor; .slice(start, end) -> Tensor; .reshape(dims: Array) -> Tensor; .sum() -> Float; .sum(axis: Long?) -> Tensor; .mean() / .mean(axis); .max() / .max(axis); .argmax(axis: Long) -> Tensor; .to_array() -> Array; .item() -> Float; .requires_grad() -> Tensor; .backward() -> Nil; .grad() -> Tensor; .zero_grad() -> Nil; .detach() -> Tensor; Tensor.use_cpu() -> Nil; Tensor.use_gpu() -> Nil; Tensor.use_auto() -> Nil; Tensor.gpu_available() -> Bool; Tensor.device() -> String
JSON — JSON.stringify(v, indent=0, sort_keys=false, lines=false) -> String; JSON.parse(s, lines=false, number_mode='auto', jsonc=false) -> Any
Args — Args.parse(argv: Array
Proc — Proc.run(cmd: Array