Skip to content

Language Quick Reference

A quick tour of Kaappi's Scheme dialect with runnable examples. For detailed procedure documentation, see the Procedure Reference. There is also a printable two-page A4 cheatsheet covering the language plus CLI, REPL, and thottam essentials.

Most examples below use procedures from (scheme base). In a file you need to import it explicitly; the REPL imports it automatically. Some examples also use (srfi 1) for filter and fold.

Numbers

Kaappi supports fixnums (63-bit integers), bignums (arbitrary precision), exact rationals, flonums (IEEE 754 f64), and complex numbers. When a fixnum operation would overflow 63 bits, the result is promoted to a bignum automatically. Exact division produces rationals, not floats — use inexact when you need a float.

(+ 1 2 3)              ;=> 6
(* 2.5 4)              ;=> 10.0
(expt 2 100)           ;=> 1267650600228229401496703205376
(/ 1 3)                ;=> 1/3
(inexact (/ 1 3))      ;=> 0.3333333333333333
(+ 1/3 1/6)            ;=> 1/2
(sqrt -1)              ;=> +i
(make-rectangular 3 4) ;=> 3+4i

Strings

Strings are UTF-8 encoded and indexed by codepoint position.

(string-length "hello")       ;=> 5
(string-ref "hello" 1)        ;=> #\e
(substring "hello" 1 4)       ;=> "ell"
(string-append "foo" "bar")   ;=> "foobar"
(string-upcase "hello")       ;=> "HELLO"
(string-length "héllo")       ;=> 5
(string-ref "lambda: λ" 8)   ;=> #\λ

Raw string literals (#"X"..."X", SRFI 267) interpret no escape sequences — backslashes and newlines are taken verbatim. The X is a per-literal delimiter, possibly empty, chosen so the content can contain double quotes:

#""C:\Users\me""            ;=> "C:\\Users\\me" — backslashes stay literal
(string-length #""x\ny"")   ;=> 4 — backslash + n, not a newline
#"end"he said "hi""end"     ;=> "he said \"hi\""

The syntax is built into the reader, so no import is needed; (import (srfi 267)) adds port procedures such as read-raw-string, write-raw-string, and generate-delimiter. See SRFI Support.

Lists

See Pairs and Lists, SRFI-1.

(cons 1 '(2 3))        ;=> (1 2 3)
(car '(a b c))          ;=> a
(cdr '(a b c))          ;=> (b c)
(list 1 2 3)            ;=> (1 2 3)
(map (lambda (x) (* x x)) '(1 2 3))  ;=> (1 4 9)
(filter odd? '(1 2 3 4 5))           ;=> (1 3 5)
(fold + 0 '(1 2 3 4 5))              ;=> 15

Vectors

;; literal vectors like #(10 20 30) are immutable — build with
;; vector (or vector-copy a literal) when you need vector-set!
(define v (vector 10 20 30))
(vector-ref v 1)        ;=> 20
(vector-set! v 0 99)
(vector-map + #(1 2 3) #(10 20 30))  ;=> #(11 22 33)

Booleans, Characters, Symbols

(and #t #f)             ;=> #f
(or #f 42)              ;=> 42
(char-alphabetic? #\A)  ;=> #t
(char-upcase #\a)       ;=> #\A
(symbol? 'hello)        ;=> #t
(eq? 'abc 'abc)         ;=> #t

Bytevectors

(define bv #u8(10 20 30))
(bytevector-u8-ref bv 0)     ;=> 10
(bytevector-length bv)        ;=> 3
(utf8->string #u8(104 101 108 108 111))  ;=> "hello"

Definitions and Functions

(define x 42)
(define (add a b) (+ a b))
(add x 8)              ;=> 50

(define greet
  (lambda (name)
    (string-append "Hello, " name "!")))
(greet "World")         ;=> "Hello, World!"

Conditionals

(if (> 3 2) "yes" "no")       ;=> "yes"

(cond
  ((< x 0) "negative")
  ((= x 0) "zero")
  (else     "positive"))       ;=> "positive"

(case (+ 1 1)
  ((1) "one")
  ((2) "two")
  (else "other"))              ;=> "two"

Binding Forms

(let ((x 1) (y 2)) (+ x y))            ;=> 3
(let* ((x 1) (y (+ x 1))) (+ x y))     ;=> 3
(letrec ((even? (lambda (n)
                  (if (= n 0) #t (odd? (- n 1)))))
         (odd?  (lambda (n)
                  (if (= n 0) #f (even? (- n 1))))))
  (even? 10))                           ;=> #t

;; Named let (loop)
(let loop ((n 5) (acc 1))
  (if (= n 0) acc
      (loop (- n 1) (* n acc))))        ;=> 120

;; do
(do ((i 0 (+ i 1))
     (sum 0 (+ sum i)))
    ((= i 5) sum))                      ;=> 10

Tail Calls

Tail calls are optimized — a call in tail position reuses the current stack frame. Write loops as recursive calls without worrying about stack overflow:

(define (countdown n)
  (if (zero? n)
      'done
      (countdown (- n 1))))   ;; tail call: constant stack space

(countdown 10000000)  ;=> done

Macros

(define-syntax my-when
  (syntax-rules ()
    ((my-when test body ...)
     (if test (begin body ...)))))

(my-when (> 3 2)
  (display "yes")
  (newline))
;; prints: yes

Exceptions

(guard (exn
        ((string? (error-object-message exn))
         (display "Caught: ")
         (display (error-object-message exn))
         (newline)))
  (error "something went wrong" 42))
;; prints: Caught: something went wrong

(with-exception-handler
  (lambda (e) (display "Error!\n") 'recovered)
  (lambda () (raise-continuable "boom")))
;=> recovered — after printing "Error!"

With plain raise the exception is non-continuable: if the handler returns, a secondary "handler returned" error is signaled. Use raise-continuable when the handler is meant to supply a replacement value, and guard (above) to catch-and-handle plain raise.

Continuations

See Control Flow.

;; Escape continuation (non-local exit)
(call/cc (lambda (exit)
  (for-each (lambda (x)
              (when (negative? x) (exit x)))
            '(1 2 -3 4))
  'all-positive))
;=> -3

For simple non-local exits like the one above, prefer call/ec — it captures a one-shot escape continuation with no stack snapshot, much cheaper than call/cc, which copies all registers and frames.

Parameters

(define my-param (make-parameter 10))
(my-param)              ;=> 10

(parameterize ((my-param 42))
  (my-param))            ;=> 42

(my-param)              ;=> 10

Lazy Evaluation

(define p (delay (begin (display "computed!\n") 42)))
(force p)  ;; prints "computed!" then returns 42
(force p)  ;; returns 42 (cached, no recomputation)

Records

(define-record-type <point>
  (make-point x y)
  point?
  (x point-x)
  (y point-y set-point-y!))

(define p (make-point 3 4))
(point-x p)             ;=> 3
(set-point-y! p 10)
(point-y p)             ;=> 10

Multiple Values

(call-with-values
  (lambda () (values 1 2 3))
  (lambda (a b c) (+ a b c)))  ;=> 6

(let-values (((a b) (values 1 2)))
  (+ a b))                     ;=> 3

Next: Libraries