Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Cheat sheet

The whole everyday language on one page. Every line below is from one file that CI typechecks and tests. The handbook explains each part, and the language reference has every rule.

Types

type Id = new Str derive Eq, Show
type Qty = Int where _ > 0
type Item = {id: Id, qty: Qty, tags: List[Str]} derive Eq, Show
type Shape = Circle{r: F64} | Rect{w: F64, h: F64} | Dot
type Pair[A, B] = {first: A, second: B}
type Err = NotFound{id: Str} | Bad

Int (i64) F64 Bool Str Unit, List[T] Opt[T] Res[T, E] Map[K, V] Set[T], tuples (A, B), functions A -> B ! e. No implicit conversions: n.to_f64, x.round, s.to_int.

Functions, contracts and matching

fn area(s: Shape) -> F64
= match s
  | Circle{r} => 3.14 * r * r
  | Rect{w, h} if w == h => w * w
  | Rect{w, h} => w * h
  | Dot => 0.0

fn clamp_pct(x: Int) -> Int
  pre x > -1000
  post r >= 0 and r <= 100
  ex clamp_pct(150) == 100
= if x < 0 then 0 else if x > 100 then 100 else x

fn first_tag[T](xs: List[T], f: T -> Bool) -> Opt[T]
= xs.find(f)

fn sides(s: Shape) -> Int
= match s
  | Circle | Dot => 0
  | Rect => 4

fn add_all(xs: List[Int]) -> Int
= match xs
  | [] => 0
  | [x, ..rest] => x + add_all(rest)

fn width_or(s: Shape, d: F64) -> F64
= if s is Rect{w} and w > 0.0 then w else d

fn round_ones(xs: List[Shape]) -> Int
= xs.filter(_ is Circle).len

Blocks, loops and lambdas

fn stats(xs: List[Int]) -> (Int, Int) ! log
= do
  total = xs.sum
  var big = 0
  for x in xs
    if x > 10 then big := big + 1
  log("total {total}, {big} big")
  (total, big)

fn labels(xs: List[Int]) -> List[Str]
= xs.map(x => do
  half = x / 2
  if half > 3 then "big {x}" else "small {x}")

Values

test values = do
  it = Item{id: Id("a"), qty: 2, tags: []}
  moved = it with qty := 3, tags := ["new"]
  p = Pair{first: 1, second: "one"}
  (a, b) = (p.first, p.second)
  [1, 2, 3].map(_ * 2) == [2, 4, 6] and moved.qty == 3 and a == 1 and b.len == 3 and "n={a}" == "n=1" and some(2).or(0) == 2 and empty_map().put("k", 1).get("k") == some(1)

Errors

fn lookup(items: List[Item], id: Str) -> Item ! fail[Err]
= items.find(_.id.raw == id).ok_or(NotFound{id})

fn qty_or_zero(items: List[Item], id: Str) -> Int
= catch lookup(items, id).qty
  | NotFound => 0
  | Bad => -1

fn qty_of(items: List[Item], id: Str) -> Int ! fail[Err]
= do
  some(item) = items.find(_.id.raw == id) else raise NotFound{id}
  item.qty

Effects and handlers

effect ask() -> Int

fn twice() -> Int ! ask
= ask() + ask()

fn answered() -> Int
= handle twice()
  | ask() => resume(21)

Traits

trait Named
  fn name(x: Self) -> Str
  fn greet(x: Self) -> Str = "hi {x.name}"

impl Named for Item
  fn name(i: Item) -> Str = i.id.raw

fn greet_all[T: Named](xs: List[T]) -> List[Str]
= xs.map(greet)

Packages

use money.{Money, fmt}
$ sspur test cheat.ssp
3 passed, 0 failed

Spelled differently

Not thisBut this
&&, ||, !and, or, not
len(xs), xs.lengthxs.len
None, null, Some(x)none, some(x)
c ? a : bif c then a else b
if let some(x) = oif o is some(x) then
let some(x) = o else { return 0 }some(x) = o else 0
[x, ...rest], [x, *rest][x, ..rest]
x += 1x := x + 1 on a var
{ in a string\{
f(g(_)) for x => f(g(x))write the lambda; _ binds to the innermost call
inner match arms at the outer arms’ columnindent the inner arms deeper

Commands

TaskCommand
Run, test, check, formatsspur run F, sspur test F, sspur check F, sspur fmt F --write
Property-test and prove contractssspur fuzz F, sspur verify F
Agent loop on a codebasesspur start NAME..., sspur q pack NAME, sspur edit --test change.ssp
Packagessspur add NAME (or a path or git URL), sspur deps update, sspur deps tree
Servicessspur deploy plan F, sspur deploy local F

The command line reference has the rest.