Skip to content

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.

Before the tour, three sentences that everything else hangs on:

  1. A model can implement a function. simulate def … by <model>: gives a function a declarative body that a language model fulfills — fenced by a sem descriptor, a token budget, and contracts that are actually checked. See /neurosymbolic/simulate/.
  2. 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/.
  3. There are no classes. Composition is traits + algebraic data types, Rust-style — not inheritance. Trait objects give you open-world polymorphism; enum + match give you closed-world exhaustiveness. See /language/traits-enums-generics/.
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 sum

Everything above is deterministic and checkable before it runs. The pieces:

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.

/language/types/

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/

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/

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/

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.

/language/error-handling/

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/

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.

/language/equations/

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 nullOption[T] / Result[T, E].
  • No try/raise/finally unwinding — typed failures + expect/except + with.
  • No assert — it is a reserved, rejected token with a fix-it to ensure/check.
  • No heterogeneous collectionslist[T], dict[K, V], set[T] are homogeneous.
  • Immutable bindings by defaultmut opts 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.