the tour

a tour of kanso

each lesson below is a program and what it printed. the programs run in your browser: press run in a panel's title to run it, edit it and run it again, and double-click the title to put it back. nothing is installed. each lesson takes a minute and links to the chapter of the book that covers the idea in full.

the tour shows the language. the book explains it, and chapter 13 onward builds and ships real programs.

01 · hello

a kanso program is a file of statements. print takes one argument, written after it with a space: there are no parentheses around arguments and no semicolons. press run on any panel on this page, change the program, and press it again.

hello.kso
print "hello, world"
kanso run hello.kso
hello, world

more in chapter 01.

02 · names and values

= binds a name to a value. text in double quotes interpolates any expression between braces.

names.kso
name = "mugi"
cups = 3
print "{name} has had {cups} cups, and wants {cups + 1}"
kanso run names.kso
mugi has had 3 cups, and wants 4

more in chapter 02.

03 · numbers

an int has no ceiling, so the product prints all twenty-two digits. dividing two ints keeps whole numbers; once a float is involved, the answer is a float.

numbers.kso
big = 1000000000 * 1000000000 * 1000
half = 7 / 2
widened = 7 / 2.0
print "{big}" .> (_ -> print "{half} and {widened}")
kanso run numbers.kso
1000000000000000000000
3 and 3.5

more in chapter 02.

04 · lists

a list is written in brackets, with spaces between the elements and no commas. indexing starts at 1. the list functions live in std/list: list/map answers a recipe, and list/to_list turns it into a list.

lists.kso
import "std/list"

teas = ["sencha" "hojicha" "gyokuro"]
loud = list/to_list (list/map teas (t -> "{t}!"))
print "first: {teas[1]}" .> (_ -> print "{loud}")
kanso run lists.kso
first: sencha
["sencha!" "hojicha!" "gyokuro!"]

more in chapter 12.

05 · maps

a map pairs keys with values. put answers a new map; the old one is unchanged, because no value in kanso is ever changed in place. entries lists the pairs in key order.

maps.kso
prices = { "dango":350 "taiyaki":500 }
prices = put prices "mochi" 300
print "{prices["mochi"]} yen" .> (_ -> print "{entries prices}")
kanso run maps.kso
300 yen
[entry "dango" 350 entry "mochi" 300 entry "taiyaki" 500]

more in chapter 02.

06 · records

a type lists named fields, and its name builds one, with the fields in the order they were declared. a binding pattern takes a record apart; a dot reads one field.

records.kso
type tea
  name
  steep

t = tea "sencha" 60
tea name seconds = t
print "{name}, {seconds} seconds" .> (_ -> print "or just {t.name}")
kanso play records.kso
sencha, 60 seconds
or just sencha

more in chapter 03.

07 · functions

fn declares a function, and its body is indented two spaces. the last line is the answer. a call is the function name followed by its arguments, and parentheses group a call that is itself an argument.

functions.kso
fn steep_for name seconds
  "steep {name} for {seconds} seconds"

print (steep_for "hojicha" 30)
kanso play functions.kso
steep hojicha for 30 seconds

more in chapter 03.

08 · overloads

a function can have several arms, and each call goes to the most specific one that fits. the literal 0 beats the plain n, so the base case of a recursion is an arm, with no if.

overloads.kso
fn fact 0
  1

fn fact n
  n * fact (n - 1)

print "20! = {fact 20}"
kanso play overloads.kso
20! = 2432902008176640000

more in chapter 03.

09 · if

if is a function of three arguments: a condition and two answers. use it for a question about one value's content. a question about what kind of value something is gets an arm instead.

if.kso
fn ticket age
  if (age < 13) "child" "adult"

print (ticket 9) .> (_ -> print (ticket 40))
kanso play if.kso
child
adult

more in chapter 03.

10 · kinds of a thing

a type with no fields is a marker: its name is its only value. a typeset names a closed set of types. an arm for each member does the work an enum and a switch do elsewhere.

markers.kso
type cold

type hot

type warm

type temperature cold hot warm

fn serve cold
  "over ice"

fn serve hot
  "in a warmed cup"

fn serve warm
  "as it comes"

print (serve hot) .> (_ -> print (serve cold))
kanso play markers.kso
in a warmed cup
over ice

more in chapter 03.

11 · nothing there

looking up a key that is not there answers none, an ordinary value. an arm takes it like any other.

none.kso
fn describe none
  "not on the menu"

fn describe price
  "{price} yen"

menu = { "dango":350 }
print (describe menu["dango"]) .> (_ -> print (describe menu["pocky"]))
kanso play none.kso
350 yen
not on the menu

more in chapter 04.

12 · failure

err makes a failure. a failure passes every function it reaches without running it, until it reaches the top of the program, which reports it with where it was born. .> runs its step on a value and steps past a failure.

failure.kso
fn share _ 0
  err "no one to share with"

fn share yen people
  yen / people

fn with_tip yen
  yen + yen / 10

print "{with_tip (share 1200 3)}"
  .> (_ -> share 1200 0 .> with_tip .> (y -> print "{y}"))
kanso play failure.kso
440
error[endpoint]: unhandled err reached the executor: "no one to share with"
  born in share at failure.kso:2

more in chapter 04.

13 · effects

print does not print. it answers a description of printing, so a description can be named and used twice. .> puts one description after another, and the runtime performs the whole thing once the program has been evaluated.

effects.kso
knock = print "kon kon"

knock .> (_ -> knock) .> (_ -> print "come in")
kanso run effects.kso
kon kon
kon kon
come in

more in chapter 05.

14 · pipes

x . f is f x, so a chain reads left to right in the order things happen.

pipes.kso
fn shout s
  "{s}!"

fn twice s
  "{s} {s}"

"irasshaimase" . shout . twice . print
kanso play pipes.kso
irasshaimase! irasshaimase!

more in chapter 05.

15 · functions as values

(p -> p < 400) is a function written inline. &add_tax 10 supplies the first argument and waits for the rest.

lambdas.kso
import "std/list"

fn add_tax rate yen
  yen + yen * rate / 100

with_tax = &add_tax 10
prices = [350 500 300]
print "{list/to_list (list/map prices with_tax)}"
  .> (_ -> print "{list/to_list (list/select prices (p -> p < 400))}")
kanso play lambdas.kso
[385 550 330]
[350 300]

more in chapter 05.

16 · sequences

list/naturals counts forever, and nothing runs until something consumes it. list/take and list/find decide how much of it is computed.

sequences.kso
import "std/list"

squares = list/map list/naturals (n -> n * n)
print "{list/to_list (list/take squares 5)}"
  .> (_ -> print "{list/find squares (s -> s > 50)}")
kanso run sequences.kso
[1 4 9 16 25]
64

more in chapter 12.

17 · at the same time

two statements with nothing between them run together, as green threads. a sleep parks one while the other works, and the order of what prints follows the numbers in the program, the same on every run.

together.kso
import "std/time"

kettle = print "kettle: on"
  .> (_ -> time/sleep 30)
  .> (_ -> print "kettle: boiled")

cups = print "cups: warming"
  .> (_ -> time/sleep 10)
  .> (_ -> print "cups: warm")

kettle
cups
kanso run together.kso
kettle: on
cups: warming
cups: warm
kettle: boiled

more in chapter 06.

18 · tests

a test is a constant whose name starts with test_ and whose value is a boolean. kanso test evaluates each one. this panel shows what the runner printed; tests run from a terminal rather than the page.

tea_test.kso
fn steep_for name seconds
  "steep {name} for {seconds} seconds"

test_steep = steep_for "sencha" 60 == "steep sencha for 60 seconds"

test_wrong_on_purpose = steep_for "sencha" 60 == "steep it"
kanso test tea_test.kso
test_steep ... ok
test_wrong_on_purpose ... FAILED (returned false)
1 passed, 1 failed

more in chapter 07, and std/expect for tests that say what they saw.

where to go next

to run kanso on your own machine, chapter 01 builds the toolchain. to learn the language properly, read the book from there in order. to see where it goes, chapter 13 builds a command-line tool from an empty directory, chapter 14 a web service, and chapter 15 measures one and ships both. the playground has a bigger editor and a repl.