Atom

type Atom<T> @abstract =
    var value : T
    let callbacks = StdList.new

    def subscribe (f : T * T -> Unit) =
        callbacks.add f
        Token { callbacks.remove f }

Атом это контейнер, хранящий значение и оповещающий о его изменениях.

type MutAtom<T> @[mut_of Atom] =
    inherit Atom<T>

    def set (x : T) =
        if x == value then return

        let prev_x = value
        value = x

        for callback in callbacks do
            callback prev_x x

MutAtom это изменяемая версия типа Atom. Имена MutAtom и mut Atom являются синонимами.

type Token =
    let f : Unit -> Unit
    let mut is_discarded = false

    def discard =
        assert not is_discarded
        is_discarded = true
        f ()

Метод subscribe возвращает объект типа Token, позволяющий отменить подписку.

var obs position = Vector3@zero
var obs origin = Vector3@zero

val global_position@obs = origin@obs + position@obs

let token = position@atom
    |> subscribe { prev_v v -> println "position changed from $prev_v to $v" }

Для привязок position и origin создаются объекты MutAtom<Vector3>. Значение global_position будет пересчитано при каждом их изменении.

Модификатор @atom возвращает контейнер. Фигурные скобки определяют анонимную функцию.

let tuple_atom = (position@atom, origin@atom) |> to_atom

let sum@atom = tuple_atom.map { u, v -> u + v }

to_atom преобразовывает кортеж атомов в атом кортежей. Из-за модификатора @atom привязка sum имеет тип Vector3, а не Atom<Vector3>.