Skip to content

Design Philosophy

Almide is the language LLMs can write most accurately.

The essence of language design for LLMs is not maximizing expressiveness, but minimizing the set of valid candidates at each generation step. Almide optimizes for minimal thinking tokens: the less an LLM has to branch over syntax, semantics, repair strategies, or missing abstractions, the faster, cheaper, and more reliable code generation becomes.

Goal: High conciseness + Low freedom

PrincipleDefinition
PredictableThe “next valid syntax, API, and semantics” can be narrowed down tightly at each generation step
LocalThe information needed to understand or modify a given location is as close as possible
RepairableWhen errors occur, the compiler returns near-unique fix candidates in few steps
CompactHigh semantic density with low syntactic noise. Strict yet concise
  1. Canonicity — There should be, in principle, only one primary way to express the same meaning
  2. Surface Semantics — Side effects, fallibility, optionality, and mutability must appear in the syntax or type
  3. Local Reasoning — The meaning of a function or expression should be largely understandable from nearby syntax alone
  4. Incremental Completion — Incomplete code is legal; one can make progress by filling typed holes
  5. Repair-First — The compiler should be a repair tool, not a rejection tool; diagnostics are structured
  6. Vocabulary Economy — The standard library has a consistent vocabulary with no synonyms
  7. No Magic — Mechanisms that change meaning at runtime, context-dependent DSLs, and implicit type conversions are prohibited
Ambiguity sourceOther languagesAlmide
Null handlingnull, nil, None, undefinedOption[T] only
Error handlingthrow, try/catch, panic, error codesResult[T, E] only
Generics<T> (ambiguous with < >)[T]
Loopswhile, for, loop, forEach, recursionfor x in xs { } + while cond { }
Early exitreturn, break, continue, throwLast expression + guard ... else
Lambdas=>, ->, lambda, fn, \x ->, blocks(x) => expr only
Statement termination;, optional ;, ASI rulesNewline-separated
Conditionalsif with optional else, ternary ?:if/then/else
Side effectsImplicit anywhereeffect fn annotation required
Operator meaningOverloading, implicit coercionFixed built-in meanings only
Type conversionsImplicit widening, coercionExplicit only
SourceWhat Almide does
Name resolutionCore modules auto-imported; non-core requires explicit import
Type inferenceLocal only — annotations required on function signatures
OverloadingNone — names do not participate in ad-hoc overload resolution
Implicit conversionsNone — int.to_string(n), never auto-coerce
Trait lookupTraits exist but all impl is explicit
Method resolutionModule-qualified function form is canonical; UFCS is sugar
Declaration orderFunctions can reference each other freely
Import styleimport module or import module as alias — no from, no *

effect fn is not primarily a safety feature — it is a search space reducer for code generation.

  • A pure function can only call other pure functions — the set of valid completions shrinks dramatically
  • An effect fn explicitly marks I/O boundaries — the LLM knows exactly where side effects are legal
  • Effect mismatch is caught at compile time — wrong calls are rejected before execution
  • Function signatures alone tell the LLM what is callable at each point, without reading function bodies

Almide keeps concurrency boring on purpose: explicit fork, explicit join, automatic cancellation, and fail-fast semantics. There is no async/await.

// Run concurrently, wait for all
fan { fetch_users(); fetch_orders() }
// Parallel map
fan.map(urls, (url) => http.get(url))
// First to complete wins
fan.race([() => fast_api(), () => slow_api()])

Rules:

  • fan { } is only valid inside effect fn
  • If any expression returns err, the entire fan fails and siblings are cancelled
  • No var capture inside fan (prevents data races)
  • No unstructured spawn — all concurrency is scoped

f(x, y) and x.f(y) are equivalent. The compiler rewrites x.f(y) to f(x, y) at parse time. Canonical form is module-qualified: string.len(s).

Each error points to exactly one repair:

'!' is not valid in Almide at line 5:12
Hint: Use 'not x' for boolean negation, not '!x'.
'return' is not valid in Almide at line 12:5
Hint: Use the last expression as the return value,
or 'guard ... else' for early exit.
ConventionRuleExample
Module prefixCanonical form is module.function()string.len(s), list.get(xs, i)
Predicate prefixis_ for boolean functionsstring.is_empty(s)
Return consistencyOption for lookups, Result for I/Olist.get() -> Option[T]
No synonymsOne name per operationlen not length/size
Symmetric pairsMatching names for inversessplit/join, to_string/to_int

These are intentional trade-offs:

SacrificedWhy
Raw expressivenessEach concept has one idiomatic way to write it
Operator overloadingOperators have fixed built-in meanings only
MetaprogrammingNo macros, no reflection, no code generation
Ad-hoc polymorphismProtocols are explicit, no implicit resolution
Multiple return stylesNo return keyword; last expression is always the value
Syntax sugar varietyOne way to write each construct
DSL capabilitiesNo operator definition, no custom syntax

These are not missing features — they are intentional constraints that keep the generation space focused.