Language Overview
Sema’s surface is Python-shaped: indentation blocks, def, struct, enum,
keyword arguments, comprehensions, and f-strings. If you can read Python, you can
read Sema. But Sema is explicitly not a Python superset — the semantics are
new, and a handful of familiar-looking constructs behave differently on purpose.
This page is the hub for the core language. It gives you the shape of everything; each subsection below links to a page that goes deep.
The three ideas that make Sema Sema
Section titled “The three ideas that make Sema Sema”Before the tour, three sentences that everything else hangs on:
- A model can implement a function.
simulate def … by <model>:gives a function a declarative body that a language model fulfills — fenced by asemdescriptor, a tokenbudget, and contracts that are actually checked. See /neurosymbolic/simulate/. - Effects are part of the type. Every function carries a capability row like
!{fs.read, model.invoke}. The deterministic core is!{}— provably no model, no I/O. The compiler tracks it; policies constrain it. See /language/functions-and-effects/. - There are no classes. Composition is traits + algebraic data types,
Rust-style — not inheritance. Trait objects give you open-world polymorphism;
enum+matchgive you closed-world exhaustiveness. See /language/traits-enums-generics/.
A one-screen tour
Section titled “A one-screen tour”from finops.domain import Currency
# An algebraic data type: a product (struct) with fields and an invariant.struct Money (Mergeable, Semantic): currency: Currency minor_units: i64 invariant minor_units >= 0 def combine(self, other: Money) -> Money !{}: require self.currency == other.currency return Money(currency=self.currency, minor_units=self.minor_units + other.minor_units)
# A sum type: exactly one of these variants, some carrying a payload.enum Escalation: none notify(channel: str) page(oncall: str, deadline: Duration)
# A trait declares required behavior + provided defaults. No base class.trait Mergeable: sem "Types with an associative combine, safe for unordered parallel reduction" def combine(self, other: Self) -> Self !{} law associative: combine(combine(a, b), c) == combine(a, combine(b, c))
# A bounded generic: works for any T that is Ord; the bound is the obligation.def maximum[T: Ord](xs: list[T]) -> T !{}: mut best = xs[0] for x in xs: best = best.max2(x) # a default method provided by the Ord trait return best
# The effect row `!{}` is a proof: this function performs no model calls and no I/O.def total(prices: list[Money]) -> Money !{}: mut sum = prices[0] for p in prices[1:]: sum = sum.combine(p) return sumEverything above is deterministic and checkable before it runs. The pieces:
Scalars and numerics
Section titled “Scalars and numerics”int (arbitrary precision by default), sized integers i8..i64 / u8..u64, and
floats f16/f32/f64 (plus bf16/f8 cast forms), bool, str, bytes.
Arithmetic is checked: overflow is a typed OverflowError, never a silent
wrap; division by zero raises, never returns NaN. Width casts (f16(x),
i8(x)) round through the real format, so a sized type is observable, not
cosmetic.
Algebraic data types — no null
Section titled “Algebraic data types — no null”struct for products and enum for sums, with generics. There is no null:
absence is Option[T] (Some(x) / None) and fallibility is Result[T, E]
(Ok(x) / Err(e)). None is a variant you consume by match or ?, never a
reference you compare for identity.
→ /language/types/ · /language/error-handling/
Traits, enums, and generics — instead of classes
Section titled “Traits, enums, and generics — instead of classes”Sema has no classes and no inheritance by design. Behavior is declared by
trait (required signatures + default methods + laws) and supplied by struct
and enum via impl or a header list. Generics are [T] with bounds ([T: Ord]), erased at runtime. Trait objects (list[Renderer]) give you open-world
polymorphism; enum + match give you closed-world exhaustiveness.
→ /language/traits-enums-generics/
Functions and effects
Section titled “Functions and effects”def name(x: T) -> R !{effects}:. The effect row is part of the signature and
part of the function type, so a higher-order function cannot smuggle effects its
own row does not admit. An omitted row is inferred (fail-closed to !{}),
never a wildcard grant. Lambdas are lambda x: e or x => e.
→ /language/functions-and-effects/ · /governance/effects/
Control flow and pattern matching
Section titled “Control flow and pattern matching”if/elif/else, for, while, with for scoped resources, and the
declarative loop … until <cond> max_iters N: for bounded agent loops. match /
case destructures structs, enums, tuples, and regex captures, with
exhaustiveness checking and guards.
→ /language/control-flow/ · /language/pattern-matching/
Errors as typed values
Section titled “Errors as typed values”No unwinding exceptions, no raise. Failures are typed values: Result[T, E],
propagated with ?, handled with flat expect … / except E as e: arms.
Contracts (require/ensure/invariant) raise ContractViolation.
Modules and operators
Section titled “Modules and operators”One .sema file is a module; a package is the tree under a sema.toml.
Declarations are private by default; pub marks the public surface. Standard
library modules import explicitly (from std.belief import Belief). Operators are
functions with symbolic names and can be overloaded per type; the equality family
(==, is, ~=) is central — ~= returns a graded Sim, not a bool.
→ /language/modules/ · /language/operators/
Equations — mathematics as syntax
Section titled “Equations — mathematics as syntax”equation blocks let you transcribe mathematical notation (∀, Σ, ∇, argmin, ‖·‖)
directly; the compiler lowers it to typed, pure, natively-executed code. Native
tensors and stdlib math bindings sit alongside.
How Sema differs from Python — the short list
Section titled “How Sema differs from Python — the short list”Sema adopts the Codon divergence list: the dynamic features that break static compilation are gone.
- No classes / inheritance / metaclasses / monkey-patching — traits + ADTs.
- No
null—Option[T]/Result[T, E]. - No
try/raise/finallyunwinding — typed failures +expect/except+with. - No
assert— it is a reserved, rejected token with a fix-it toensure/check. - No heterogeneous collections —
list[T],dict[K, V],set[T]are homogeneous. - Immutable bindings by default —
mutopts into rebinding; values are value-semantic. - Checked arithmetic — overflow and division-by-zero raise, no silent wrap or
NaN.
Everything that parses must have an effect or fail loudly — Sema’s no silent
no-ops ethos. sema check flags any directive it does not recognize, so a typo
never quietly does nothing.