A statically-typed procedural language that is a mix of C, Haskell and Python. It compiles via a C backend or can be run directly as a script.
reminders = filename
File.read-contents(al)
lines()
filter(fn s: not s is-blank())
zip(from(1))
The most unique feature of the language is the handling of function environments. This allows for Python/dynamic language-esque function nesting without needing an allocator.
In most languages you either allocate closures on the heap (Haskell, Python) or pass context explicitly (C, Zig) or have a very limited ability to use functions with environments (Rust’s Fn..<> traits).
In case of typeclasses, languages forbid local instances entirely (Haskell’s global-instance coherence requirement, Rust’s impl blocks).
Here, in kkc, I try to maximize expressiveness without depending on any external system for allocation. Because the type system tracks environments through inference, the compiler always knows the full shape of a function’s captured state at compile time.
This makes code like this possible:
fn f() -> I32 -> I32
sumtin = 420
inst D I32 # instance definition
d (x I32) -> I32
return x + sumtin # captures sumtin
return d # function escapes - sumtin travels with it
println(f()(69)) # prints 489
I’m maximizing expressiveness but adhering to the constraints of a low level language, theoretically making kkc very portable while not compromising on any of its features.
[]) operator to custom lists and hash maps'\(x) with \(y)'map-filter-reduce style codeCartesian product between two iterables:
fn cartesian (lit, rit): lit
map(fn x: rit map(fn y: (x, y)))
flatten()
Part of a makefile-esque script:
if not opt('clean') and 'prog' deps (['src'])
'rebuilding' println()
'cc -O3 -o prog src/main.c' Sh.run(al)
Setting the cells of a screen (with external environment):
s chars() zip(from(0)) for-each(fn((c, xx)))
Slice.set(screen&.current, i + xx i32-size(), Cell { c, fg, bg })
Requires Zig 0.13.
zig build # build the compiler → zig-out/bin/kkc
# optionally move it to a PATH reachable place.
./install.sh # install to ~/.local/bin/
# Don't forget to set the KKC_STD
zig build run -- <file.kkc> # run via interpreter (default)
zig build run -- --backend c <file.kkc> # compile to native binary via C and run
Or with the installed binary:
kkc <file.kkc>
kkc --backend c <file.kkc>
Environment variable: KKC_STD — path to the standard library. Defaults to std/ relative to the binary.
zig build test # run all tests
zig build test -- <prefix> # run tests matching a prefix
zig build test -- -f # run only failing tests
Tests live in test/tests/ as .kkc files with embedded expected output.
The stdlib is written in kkc. prelude.kkc contains compiler primitives. converged.kkc contains default exports.
| Module | Contents |
|---|---|
Slice |
Slices and basic operations |
List |
Arraylist |
Str |
Strings |
Iter |
Iterators |
Array |
Fixed-size arrays |
Hash |
Hash map |
Math |
Arithmetic utilities |
File |
File I/O |
Sh |
Shell commands |
Mem |
Memory / casting utilities |
Alloc |
Allocators |
Term |
Printing and ANSI terminal primitives |
Tui |
Terminal UI (screen buffer, input, mouse) |
In active development.
The core is finished, so now I’m polishing up all the rough edges: