Language Tour
This tour introduces Kit's core concepts in a hands-on way. Each section includes runnable examples you can try yourself.
Comments
Comments in Kit start with # and continue to the end of the line:
# This is a comment
x = 42 # Comments can also appear after code
Doc Comments
Doc comments start with ## and provide structured documentation for modules,
functions, and types. They're similar to Python docstrings or JSDoc comments.
## Calculate the factorial of a number.
##
## Computes n! using recursive multiplication.
## Returns 1 for n <= 1.
##
## Parameters:
## n - A non-negative integer
##
## Returns:
## The factorial of n
##
## Example:
## factorial 5 # => 120
factorial = fn(n) =>
if n <= 1 then
1
else
n * factorial (n - 1)
Module-level doc comments appear at the top of a file, before the module declaration:
## Math utilities for Kit.
##
## This module provides common mathematical functions
## including factorial, fibonacci, and prime checking.
##
## Example:
## import Math
## Math.factorial 5 # => 120
module Math
## Check if a number is prime.
export is-prime? = fn(n) => ...
Values and Bindings
Kit uses = to bind values to names. Bindings are immutable by default:
# Bind values to names
name = "Kit"
age = 1
price = 19.99
active? = true
# String interpolation with ${...}
message = "Hello, ${name}!"
println message # => Hello, Kit!
Heredocs
For multi-line strings, use heredocs with <<~DELIM ... DELIM. Common indentation is automatically stripped:
# Multi-line string with automatic indentation stripping
html = <<~HTML
<div class="container">
<h1>Welcome</h1>
<p>Hello, world!</p>
</div>
HTML
# Heredocs support interpolation
user = "Alice"
greeting = <<~END
Dear ${user},
Welcome to Kit!
END
# Great for SQL queries
query = <<~SQL
SELECT id, name, email
FROM users
WHERE active = true
ORDER BY name
SQL
Functions
Functions are defined with fn and use => for the body:
# Single-line function
double = fn(x) => x * 2
# Multi-parameter function
sum = fn(a, b) => a + b
# Call functions
println (double 5) # => 10
println (sum 3 4) # => 7
Functions are first-class values and can be passed around:
# Higher-order functions
apply-twice = fn(f, x) => f (f x)
result = apply-twice double 5
println result # => 20
The Pipe Operators
Kit has two pipe operators for chaining function calls:
|>data-first (thread-first) - inserts value as the first argument|>>data-last (thread-last) - inserts value as the last argument
Data-First Pipe (|>)
Most list functions in Kit expect the list as the last argument, but the data-first pipe inserts into the first position:
# Without pipes (nested calls)
result1 = fold (fn(a, x) => a + x) 0 (map double (filter (fn(x) => x > 2) [1, 2, 3, 4, 5]))
# With data-first pipe (readable chain)
result2 = [1, 2, 3, 4, 5]
|> filter (fn(x) => x > 2) # [3, 4, 5]
|> map double # [6, 8, 10]
|> fold (fn(a, x) => a + x) 0 # 24
Data-Last Pipe (|>>)
Use the data-last pipe when you want to insert the value as the last argument. This is useful for functions like String.join:
# String.join expects: join separator list
# With data-last pipe, the list goes in as the last argument
csv = ["apple", "banana", "cherry"]
|>> String.join ", "
# => "apple, banana, cherry"
# Compare: x |> f y z becomes f x y z (x is first)
# x |>> f y z becomes f y z x (x is last)
Lists
Lists are ordered collections of elements of the same type:
# Create lists with square brackets
numbers = [1, 2, 3, 4, 5]
names = ["Alice", "Bob", "Carol"]
empty = []
# Common list operations
println (length numbers) # => 5
println (head numbers) # => 1
println (tail numbers) # => [2, 3, 4, 5]
println (reverse numbers) # => [5, 4, 3, 2, 1]
# Add elements
with-zero = cons 0 numbers # [0, 1, 2, 3, 4, 5]
Records
Records are collections of named fields:
# Create records with curly braces
person = {name: "Alice", age: 30, active?: true}
# Access fields with dot notation
println person.name # => Alice
println person.age # => 30
# Nested records
user = {
name: "Bob",
address: {
city: "New York",
zip: "10001"
}
}
println user.address.city # => New York
Pattern Matching
Pattern matching with match is Kit's primary control flow mechanism:
# Match on values
describe = fn(n) =>
match n
| 0 -> "zero"
| 1 -> "one"
| _ -> "many"
# Match on list structure
sum-list = fn(list) =>
match list
| [] -> 0
| [x | rest] -> x + sum-list rest
println (sum-list [1, 2, 3]) # => 6
Algebraic Data Types
Define custom types with type:
# Simple enumeration
type Color = Red | Green | Blue
# Parameterized types with data
type Shape = Circle Float
| Rectangle Float Float
| Point
# Use pattern matching with ADTs
area = fn(shape) =>
match shape
| Circle r -> 3.14159 * r * r
| Rectangle w h -> w * h
| Point -> 0.0
shape = Rectangle 4.0 5.0
println (area shape) # => 20.0
Kit includes built-in Option and Result types for handling optional values and errors:
# Option: Some a | None (for optional values)
find-user = fn(id) =>
if id == 1 then
Some "Alice"
else
None
match (find-user 1)
| Some name -> println "Found: ${name}"
| None -> println "Not found"
# Result: Ok a | Err e (for error handling)
safe-div = fn(x, y) =>
if y == 0 then
Err "division by zero"
else
Ok (x / y)
match (safe-div 10 2)
| Ok value -> println "Result: ${value}"
| Err msg -> println "Error: ${msg}"
Conditionals
Use if-then-else expressions:
absolute = fn(n) =>
if n < 0 then
-n
else
n
grade = fn(score) =>
if score >= 90 then
"A"
else if score >= 80 then
"B"
else if score >= 70 then
"C"
else
"F"
Map, Filter, Fold
The three core list operations for functional programming:
numbers = [1, 2, 3, 4, 5]
# Map: transform each element
doubled = map (fn(x) => x * 2) numbers
# => [2, 4, 6, 8, 10]
# Filter: keep elements matching a predicate
evens = filter (fn(x) => x % 2 == 0) numbers
# => [2, 4]
# Fold: reduce list to a single value
total = fold (fn(acc, x) => acc + x) 0 numbers
# => 15
# Chain them together
result = numbers
|> filter (fn(x) => x > 2)
|> map (fn(x) => x * x)
|> fold (fn(acc, x) => acc + x) 0
# => 50 (9 + 16 + 25)
Iteration
Kit has a for loop for iterating over collections:
# Basic for loop
for x in [1, 2, 3] =>
println "Number: ${x}"
# Generate ranges with range
for n in range 1 6 =>
println n
# Prints: 1, 2, 3, 4, 5
# Pattern matching in for loops
pairs = [(1, "one"), (2, "two"), (3, "three")]
for (num, name) in pairs =>
println "${num} is ${name}"
The for loop is syntactic sugar that desugars to each.
You can also use each directly with pipes:
# Using each with pipes
[1, 2, 3] |> each (fn(x) => println x)
# Classic FizzBuzz
fizzbuzz = fn(n) =>
if n % 15 == 0 then
"FizzBuzz"
else if n % 3 == 0 then
"Fizz"
else if n % 5 == 0 then
"Buzz"
else
to-str n
range 1 16
|> map fizzbuzz
|> each println
For accumulating results while iterating, use fold instead:
# Sum numbers from 1 to 100
total = range 1 101 |> fold (fn(acc, n) => acc + n) 0
println total # => 5050
Compile-Time Macros
Kit supports user-defined macros that expand at compile time. Macros let you extend the language with new control flow constructs, create DSLs, and generate code while preserving type safety.
# Define a macro with quasiquotation
macro unless cond then-val else-val =
`(if (not $cond) then $then-val else $else-val)
# Use the macro like a function
result = unless((1 == 2), 42, 0) # => 42
# Arithmetic macros
macro double x = `($x + $x)
macro square x = `($x * $x)
println double(5) # => 10
println square(4) # => 16
Macro syntax uses:
`(expr)— Quasiquote: creates a template expression$name— Unquote: substitutes parameter value$(expr)— Unquote expression: evaluates and substitutes
# More complex macro examples
macro when-val cond val = `(if $cond then $val else 0)
macro both? a b = `($a and $b)
# Nested macro usage
macro quad x = `(double(double($x)))
println quad(3) # => 12
Testing
Kit has built-in support for testing:
# Define tests with the test keyword
test "addition works"
assert-eq! (2 + 3) 5
test "list operations"
nums = [1, 2, 3]
assert-eq! (length nums) 3
assert-eq! (head nums) 1
assert-true! (contains? 2 nums)
Run tests with:
kit test my-tests.kit
For property-based testing, see kit-quickcheck.
Next Steps
Now that you've seen the basics, explore more of Kit:
- Standard Library - Built-in modules and functions
- List - List operations and transformations
- String - String manipulation functions
- Packages - Extend Kit with community packages