Advanced Features¶
Concurrency¶
Kaappi offers two concurrency models: green threads (fibers) for cooperative multitasking and OS threads (SRFI-18) for true parallelism.
Green threads (fibers)¶
Fibers run cooperatively within a single OS thread. They are lightweight and communicate via channels:
(import (kaappi fibers))
(define ch (make-channel))
(spawn (lambda ()
(channel-send ch "hello from fiber")))
(display (channel-receive ch)) ;=> hello from fiber
Use fibers for concurrent I/O, event loops, and cooperative task scheduling. See the Fibers reference for the full API.
OS threads (SRFI-18)¶
Real OS threads via pthread_create. Each thread gets its own VM and GC
with an independent heap. Requires the --experimental-threads flag:
(import (srfi 18))
(define t (thread-start!
(make-thread
(lambda ()
(* 6 7)))))
(thread-join! t) ;=> 42
Values are deep-copied when crossing thread boundaries:
- At
thread-start!: the thunk closure is deep-copied from parent to child - At
thread-join!: the result is deep-copied from child to parent
Threads cannot share mutable heap state directly -- use return values or channels to communicate. See the SRFI-18 reference for mutexes, condition variables, and the full threading API.
FFI (Foreign Function Interface)¶
Call C library functions directly from Scheme:
(import (kaappi ffi))
;; Open a shared library
(define libm (ffi-open "libm.dylib")) ;; macOS
;; (define libm (ffi-open "libm.so.6")) ;; Linux
;; Bind a C function: (ffi-fn lib "name" (param-types ...) return-type)
(define c-sqrt (ffi-fn libm "sqrt" '(double) 'double))
(define c-pow (ffi-fn libm "pow" '(double double) 'double))
(c-sqrt 2.0) ;=> 1.4142135623730951
(c-pow 2.0 10.0) ;=> 1024.0
;; Clean up
(ffi-close libm)
Supported C types: int, long, double, float, string, pointer,
void, bool, uint8, int8, int16, int32, int64, uint16,
uint32, uint64, size_t, char.
FFI callbacks — pass Scheme procedures to C functions that expect function pointers:
(define cb (ffi-callback (lambda (a b) (- a b)) '(pointer pointer) 'int))
;; Pass cb to a C function like qsort
(ffi-callback-release cb) ;; free when done
REPL Commands¶
The REPL supports meta-commands prefixed with , (comma). Type ,help
to see the full list:
| Command | Description |
|---|---|
,time <expr> |
Measure execution time of an expression |
,profile <expr> |
Profile timing, call counts, and allocations |
,expand <expr> |
Show the result of macro expansion |
,env [prefix] |
List global bindings (optional prefix filter) |
,gc |
Show garbage collector statistics |
,break <name> |
Set a breakpoint on a function (see Debugger below) |
,help |
Show all available commands |
kaappi> ,time (fib 30)
fib(30): 0.173s
kaappi> ,env string-
string-append string-copy string-length ...
Bytecode Caching¶
Kaappi automatically caches compiled bytecode to .sbc files next to the
source. On subsequent runs, if the source hasn't changed, the cached bytecode
is loaded directly -- skipping the reader, expander, and compiler stages.
# Explicitly compile to bytecode
kaappi --compile program.scm
# Output: Compiled program.scm -> program.sbc
# Subsequent runs use the cache automatically
kaappi program.scm
Debugger¶
The REPL includes a built-in stepping debugger.
Setting breakpoints:
Running with breakpoints:
When a breakpoint is hit, the debugger pauses and shows a debug> prompt:
Debugger commands:
| Command | Short | Action |
|---|---|---|
step |
s |
Step into the next expression |
next |
n |
Step over (stay in current frame) |
continue |
c |
Continue to next breakpoint |
locals |
l |
Show local variable bindings |
backtrace |
bt |
Print the call stack |
quit |
q |
Exit the debugger |
Other REPL debug commands:
,break name -- Set a breakpoint on a function
,breakpoints -- List all breakpoints
,delete all -- Remove all breakpoints
,step (expr) -- Step through an expression from the start
Next: CLI Reference