a tutorial
Learn wick in 10 minutes
Ten short steps. Each has a code box you can edit and run. Each step has its own fresh wick environment, so changes in one step don't leak into the next. The full REPL is one click away when you outgrow the tutorial.
1. Hello
A Lisp expression is a list, and the first thing in the list is the operator. (+ 1 2) means "call + with 1 and 2." That's the whole syntax. Once you see it, you see it everywhere.
2. Names
def binds a value to a name. After the binding, the name itself is an expression that returns the value. Code runs top to bottom, so def happens before *.
3. Functions
fn makes a function. (fn (n) (* n n)) reads as "a function of n that returns n times n." Combine with def to give it a name, then call it like any other operator.
4. Lists
Lists are the bones of Lisp. list makes one. car returns the first element; cdr returns everything after. cons puts a new element on the front. (The names are old. They predate "head" and "tail.")
5. Map and range
Functions are values. They can be passed to other functions. map takes a function and a list and returns the list of results. range generates lists of integers, which means you rarely have to write a loop.
6. If, and everything as an expression
if picks one branch or the other and returns its value. There is no statement-vs-expression split here — if is a value, just like a number. cond is a chain of ifs for when one isn't enough.
7. Recursion
A function can call itself. Factorial is the canonical demonstration. wick has tail-call optimization, which means recursive calls in the tail position don't grow the stack — the count-down at the end runs a hundred thousand iterations and returns cleanly.
8. Closures
When a function references a variable from the surrounding scope, it captures that variable — the function carries its own little environment with it. make-counter below produces a fresh counter every time it's called, each one with its own private n.
9. Dicts
Lists are the bones; dicts are how you carry named data. (dict "k1" v1 "k2" v2) builds one. dict-get reads a key (with an optional default for missing keys); dict-set returns a new dict with the key added or replaced — the original is untouched. Same shape as cons with lists: every change makes a new value, the old one stays as it was.
10. That’s wick
That's the whole language, more or less. Special forms (quote, if, cond, def, set!, fn, let, begin, and, or), a small set of primitives (arithmetic and comparison, cons, car, cdr, list, null?, pair?, eq?, not, apply, print, display, newline, mod, string-length, string-append, number->string, string->number, the dict family dict / dict-get / dict-set / dict-del / dict-has? / dict-keys / dict-values / dict-size / dict?), and a stdlib written in wick itself (map, filter, fold, reverse, range, length, sum, product, take, drop, nth, last, append, inc, dec, zero?, even?, odd?, abs, min, max, member?, sort). The Go build also has read-file / write-file / append-file / file-exists?, which is enough to script real things from disk. The full REPL is here when you want to keep going. Source: github.com/pw/Wick.