1. Elevator pitch
Hanki is a statically-typed language with Ruby/Crystal-flavored syntax, Erlang-style actors, and a typed effect-marker system. Pure functions and actions share a single keyword (def); the ! suffix on the name is what distinguishes the two. Hot reload at actor boundaries is a primary feature.
The toolchain has two tiers, built from one front end: a bytecode interpreter with a REPL (hanki run), and an ahead-of-time LLVM compiler (hanki build). Both are equally supported production modes; §22 gives the parity requirement and how it is enforced.
use io
def greet(name: string) -> string
"Hello, #{name}"
end
def main!(args: List<string>) -> () [io]
io.print!(greet("world"))
end
The three layers
Hanki has one effect system - the effect row […] carried by a function's type (§6) - and three layers of code built on it:
- Pure functions -
def foo, no!. No effects; cannot call an action; cannot crash. (Totality here means no effects and no crash - termination is not checked, so a puredefmay still loop forever.) The effect-free base. - Actions -
def foo!. Synchronous effectful computation: the!authorises effects and the row says which ([io],[throws E], …). Actions are the vocabulary of effects - every side effect a program performs is performed by an action, on the caller's own stack, returning a value directly. - Actors -
actor Foo(§15). Concurrent, share-nothing entities with privatestateand a mailbox. An actor is built from actions: everyonhandler is an action (it carries an effect row, implicitly[state]), and only an action canspawnan actor or send it a message.
The layers nest: pure code knows nothing of effects; actions add effects but stay synchronous and stack-based; actors add concurrency and isolation on top of actions. main! is itself an action - the program's root actor - so every effect in a running program happens within some actor.
Actions and actors are deliberately not one construct. Performing an effect (a synchronous call - cheap, returns a value) and being a concurrent entity (a spawned actor with its own identity, mailbox, thread, and deep-copied messages) are different operations; collapsing them would hide that difference, not remove it. The effect row is the single concept that unifies all three layers.