Semicolons will be added to the token stream, using the following rules:
TODO
Primitive types are Integer
, Float
, String
and pairs denoted by (_, _)
.
nox> 42
:: Integer
=> 42
nox> 1.2
:: Float
=> 1.2
nox> "Hello!"
:: String
=> "Hello!"
nox> (1, "test")
:: (Integer, String)
=> (1, "test")
Tuples are sugar for nested pairs.
TODO: more on this one
nox> (1, 2, 3) == (1, (2, 3))
:: Boolean
=> True
x.negate
is syntactic sugar for negate(x)
x.add(y)
is syntactic sugar for add(x, y)
lambdas are defined by pattern maching. ~
symbol defines a match clause.
nox> let identity = {~ x => x }
:: a -> a
nox> let swap = {~ (x, y) => (y, x) }
:: (a, b) -> (b, a)
nox> let even? = {
| ~ 1 => False
| ~ 2 => True
| ~ n => (n - 1).even?
| }
:: Integer -> Boolean
We can match on input by piping to a lamda:
condition.{
~ True => "Yes!"
~ False => "No"
}
type Boolean {
// these are `Boolean` constructors
False
True
}
// `value` is a type parameter
type Option(value) {
None
Some(value)
}
define or_else(option: Option(value), default: value) -> value =
option.{
~ None => default
~ Some(value) => value
}
type Ordering {
Less
Equal
Greater
}
nox> let x = None
:: Option(a)
nox> let y = Some(10)
:: Option(Integer)
nox> x.or_else(12)
:: Integer
=> 12
nox> y.or_else(12)
:: Integer
=> 10
// this `List` is in types namespace
type List(item) {
Nil
// this `List` is in values namespace
List(item, List(item))
}
type User {
User[name: String, age: Integer]
}
type Tree(item) {
Leaf
Node[left: Tree(item), value: item, right: Tree(item)]
}
define node(value: item) -> Tree(item) =
Node[left=Leaf, value, right=Leaf]
define depth(tree: Tree(item)) -> Integer =
tree.{
~ Leaf => 0
~ Node[left, right] => max(left.depth, right.depth) + 1
}
Record construction/update
nox> let joe = User[name="joe", age=42]
:: User
nox> let jack = joe[name="jack"]
:: User
nox> let tree = Node[
| left = node(1),
| value = 2,
| right = Node[
| left = node(3),
| value = 4,
| right = node(5)
| ]
| ]
:: Node(Integer)
nox> tree.depth
:: Integer
=> 3
class Equitable(value) {
define (==)(x: value, y: value) -> Boolean
// method with default implementation
define (!=)(x: value, y: value) -> Boolean =
!(x == y)
// having explains expected behavior of class methods (sometimes called class laws)
// by a list functions with Boolean return values
having {
// read this as: for all x. expect x == x to be true
reflexivity(x) =
x == x
symmetricity(x, y) =
x != y || y == x
transitivity(x, y, z) =
x != y || y != z || (x == z)
}
}
// defining class instance
define Equitable(Boolean) {
// type annotations are optional for defining instane methods
define (==)(x, y) = x.{
~ True => y
~ False => !y
}
}
// defining class instance with constraints
having Equitable(value)
define Equitable(Option(value)) {
define (==) = {
~ (Some(x), Some(y)) => x == y
~ _ => False
}
}
// classes can extend others
class Ordered(value) extend Equitable(value) {
define compare(x: value, y: value) -> Ordering
// classes can provide default implementation for super classes
define (==)(x, y) = x.compare(y) == Equal
}
class Combinable(value) extends Equitable(value) {
define combine(x: value, y: value) -> value
// methods can use class parameters on return value only
define neutral: value
having {
associativity(x, y, z) =
x.combine(y).combine(z) == x.combine(y.combine(z))
identity(x) =
x.combine(neutral) == x &&
neutral.combine(x) == x
}
}
// using classes as constraints on type variables
having Accumulatable(data) & Combinable(item)
define combine_all(data: data(item)) -> item =
data.accumulate(neutral, combine)
// classes can have multiple parameters
class Cast(from, to) {
define cast(value: from) -> to
}
// associated type parameters
class Collection[item](data) {
define empty: data
define insert(data: data, item: item) -> data
}
define Collection[item](List(item)) {
define empty = Nil
define insert(list, item) = List(item, list)
}
define Collection[(key,value)](HashMap(key, value)) {
// ...
}
having Accumulatable(data) & Collection[item](collection)
define into(data: data, collection: collection) -> collection =
data.accumulate(collection, insert)