Skip to content

Work with a little data

Let's turn a short list of orders into something useful. You can paste each complete example into orders.kiroha and run:

kiroha run orders.kiroha --json

Comments show the value represented by the CLI's tagged result. If that wrapper is new to you, Your first program explains how to read it.

Describe an order

A record groups named values. An array holds a list of values:

orders = [
  {item:"Tea", price:2.5, quantity:2},
  {item:"Cake", price:4.2, quantity:1},
  {item:"Coffee", price:3, quantity:3}
];
orders[0].item
// "Tea"

orders[0] is the first order. .item reads its item field. There are no trailing commas after the last field or array item.

Calculate a value for each item

map creates a new list by applying a callback to each item:

orders = [
  {item:"Tea", price:2.5, quantity:2},
  {item:"Cake", price:4.2, quantity:1},
  {item:"Coffee", price:3, quantity:3}
];
orders.map{order => order.price * order.quantity}
// [5,4.2,9]

orders is the receiver of .map. The callback describes the result for each item. Use orders.size when you want the number of orders.

Keep the items you want

filter keeps items when its callback returns true:

orders = [
  {item:"Tea", price:2.5, quantity:2},
  {item:"Cake", price:4.2, quantity:1},
  {item:"Coffee", price:3, quantity:3}
];
orders.filter{order => order.quantity >= 2}.map{order => order.item}
// ["Tea","Coffee"]

Each step produces a new value; the original orders value stays the same. You can put each .filter or .map on a new line to make the steps easier to follow.

Add up exact amounts

orders = [
  {item:"Tea", price:2.5, quantity:2},
  {item:"Cake", price:4.2, quantity:1},
  {item:"Coffee", price:3, quantity:3}
];
orders.map{order => order.price * order.quantity}.sum()
// 18.2

The amounts are exact decimals. sum() adds the numeric values, including decimal fractions, without converting them to binary floating point.

Check the shape of incoming data

A schema describes the shape you expect. .as[...] validates a value and returns it unchanged when it matches:

type Order = {item:str, price:num, quantity:int};
orders = [{item:"Tea", price:2.5, quantity:2}];
orders.as[[Order]].map{order => order.item}
// ["Tea"]

str, num and int mean string, number and integer-valued number. [Order] describes a list whose members all match Order. A record schema is closed by default: extra fields are rejected. Use open(Order) if extra JSON fields should be allowed and kept.

You now have a few building blocks for JSON data. Next, read some JSON over HTTP, or keep the built-in reference nearby for functions such as sort, group and fold.