Reductions
Reduction takes a function or a data structure and produces a result.
A is int->>int = (,). // A is an empty dictionary
A 2->3. // Mutation: A is now a dictionary (2->3)
_print (A 2). // Reduction: this will print "3"
Prints:
3
Reductions with Default
It is often convenient to ensure that a collection, such as a map or an array, has appropriate elements before retrieving an element as part of an operation.
For example, consider this code:
PeoplesList is str->>($first_name->str, $last_name->str, $city->str) = (,).
if (PeoplesList "Alex" == NIL) then
PeoplesList "Alex" -> ($first_name->"Alex", $last_name->"", $city->"").
end
if (PeoplesList "Alex" $last_name == NIL) then
PeoplesList "Alex" $last_name -> "Johnson".
end
Using the keyword default
, you can shorten the code significantly:
PeoplesList is str->>($first_name->str+, $last_name->str+, $city->str+) = (,).
if (PeoplesList "Alex" default ($first_name->"Alex", $last_name->NIL, $city->NIL) $last_name == NIL ) then
PeoplesList "Alex" $last_name -> "Johnson".
end
To summarize, a reduction with a default
keyword includes automatically-generated code to mutate the data structure to conform to a certain standard before the reduction takes place, avoiding extra verbose checks and the potential for encountering NIL
values.
Low-lexicographic Priority Reduction Expressions
With curry notation, which is left-associative, it is often necessary to use parentheses to separate a reduction in one of the arguments to a higher level reduction, such as in the expression: _assert (test_func 1)
. As a syntactic convenience, MUFL provides a reduction syntax with low parsing priority by using the <<
operator:
_assert << test_func 1. // Equivalent to _assert (test_func 1).
In general, a << b << c << d
is right-associative and is equivalent to a (b (c d))
.
Reduction expressions and arithmetic, when mixed, always require parentheses to avoid confusion:
(a b) + 1. // valid
a (b + 1). // valid
a b + 1. // invalid
Mutations
The statement x->y
mutates the value named by x
to become equal to y
at the next state of the packet. x
could be any variable, a dereference expression or a reduction expression. In the latter case, the mutation ensures that the dictionaries referred to by the reduction expression x
are updated correctly.
For example:
x is int->>int->>int = (,). // empty dictionary of type any
x 1->(,). // add an empty dictionary into x under key 1
x 1 2->3. // add element (2->3) into the new dictionary (x 1)
While it is possible to mutate local variables inside a function (for example, to create a loop counter), it is not possible to construct references to local function-level variables or to mutate local variables of an enclosing function in an enclosed function.
Deletion
The statement delete x
is effectively identical to x->NIL
. Any expression x
allowed in a mutation is allowed in the deletion.