fn greet name
"hello, {name}"
fn main
"kanso" . greet . print
hello, kanso
anything a style guide, linter, or code review would enforce by convention, kanso enforces by making the alternative a compile error or unrepresentable.
kanso is defined less by what it adds than by what it makes unnecessary. every derivable fact lives in tooling; the source keeps only what the compiler cannot know.
print "hi" returns a description of printing; nothing executes until the runtime receives main's description. effect sets are inferred and propagate up the call graph — no async/await, no function coloring, zero overhead for pure calls. tests assert on descriptions; no mocks.
no exceptions, no panics — and no ok/some wrappers either. success is the bare value; err reason and none are ordinary types that propagate on their own. an err reaching main unhandled is a compile error, not a crash.
values may inhabit typesets, and the only way out is dispatch. no match, no instanceof, no tag tests, no narrowing syntax. overloads dispatch on literals, concrete types, or typeset guards — resolved statically, and monomorphic code carries no tags.
no interface, class, or instance construct exists. a generic function's requirements are inferred from its body — minimal by construction, transitive through call chains. the lsp renders the effective contract; publish tooling diffs it and enforces semver.
one rendering per program. non-canonical whitespace is a syntax error; fields, imports, and typeset members are alphabetical, enforced. no formatter tool exists — there is nothing left to format.
values are immutable, so the heap is a dag, so reference counting is complete. perceus-style: counts elided statically, frees inserted at last use, in-place update under unique ownership. no lifetimes, no memory syntax in source.
every sample below is verbatim from examples/ in the repository.
safe_ratio 10, 0 returns an err — division by zero is a value, not a panic. it flows through untouched until describe dispatches on it: one overload for err reason, one for the bare number. no wrapper to unwrap, no exception to catch.
fn describe (err reason)
"failed: {reason}"
fn describe n
"result: {n}"
fn main
good = safe_ratio 10 2
bad = safe_ratio 10 0
print (describe good) >> print (describe bad)
fn safe_ratio a b
a / b
result: 5
failed: division by zero
fn fact 0
1
fn fact n
n * fact (n - 1)
fn main
answer = fact 20
print "20! = {answer}"
20! = 2432902008176640000
literal 0 outranks the generic overload — the base case is dispatch, not a conditional. and int is arbitrary-precision by default, so 20! just works.
type user
admin: bool
name: string
fn main
clay = user true "clay"
print (welcome clay)
fn welcome (user _ name)
"irasshaimase, {name}"
irasshaimase, clay
every type is a single-constructor record; fields are alphabetical, enforced. construction is positional and destructuring is how you take records apart.
fn main
print "one" >> print "two" >> print "three"
one
two
three
>> sequences descriptions without passing data. together with ., it is the complete vocabulary of "before" — everywhere else, the runtime owns order.
fn describe none
"no ninth price"
fn describe x
"ninth price: {x}"
fn main
prices = [30 10 20]
doubled = map prices (x -> x * 2)
ninth = at prices 9
print "sorted: {sort prices}" >> print "doubled: {doubled}" >> print (describe ninth)
no panicking access anywhere: at prices 9 returns none, which propagates until a describe overload dispatches on it. sort prices needs no interface — compare derives structurally. indexing is 1-based, everywhere, no exceptions.
the v0.1 specification (july 2026) is the authoritative record of every design decision to date. anything marked open is not yet decided — and it says so.
a tree-walking interpreter in rust, built query-based from day one so the lsp shares the engine. phase 0 comes first: a paper proof that inference and dispatch — the language's two founding features — are mutually consistent.
clone, build, run. the interpreter is under construction — the examples are the golden-file corpus it is built against.
$ git clone https://github.com/ClayShentrup/kanso
$ cd kanso
$ cargo build --release
$ ./target/release/kanso run examples/hello.kso
hello, world