Taking spreadsheet type processing as the target environment there are a few generic observations that can be made.
There are two types of values that can be utilized :
Constant values are numbers strings and boolean constants:
| In Formula | Evaluates as |
hello |
Java string hello |
'hello world' |
Java string hello world |
'hello ''world''' |
Java string hello 'world' |
'hello \"world\"' |
Java string hello "world" |
#t |
Java boolean Boolean.TRUE |
#f |
Java boolean Boolean.FALSE |
10 |
Java Double new Double(10) |
10.5 |
Java Double new Double(10.5) |
Computed Values can be further broken down as :
For example, a sum computation is made over a set of values - defined by a
set of objects and a specified property of each member.
While a * formula computation would require a list of values, any of which could be
a Constant or Computed value.
The simplest way to understand this is through an example. But first we need to understand a few formula primitives :
This is really the key primitive. With it you are able to access values of the object that provides the computational context, eg:
item.set("value", 10);
item.define("net", "(-> value)");
In this trivial example the resulting property "net" is a computed alias to the "value" property, anytime the "value" property is modified, the computed "net" value is updated.
Primitives are defined for multiplication [(* 2 3)] and addition
[(+ 2 3 4)] for example.
A number of primitives are provided to operate over sets of objects - sum, avg,
count, stddev - for example.
Consider a basket of items. Each item has a value, the basket should define a calculation to determine the net, vat and gross values of the basket.
The "net" value of the basket is the sum of all the value properties of the items in the basket.
basket.define("net", "(sum basket value)");
The "vat" value is the result of the "net" value multiplied by 0.175 (17.5%).
basket.define("vat", "(* (-> net) 0.175)");
And the "total" value is the sum of the "net" value and the "vat" value.
basket.define("total", "(+ (-> net) (-> vat))");
Now as items are added to the basket and modified, the basket's calculated values are kept uptodate.
item1.set("value", 10);
item1.set("basket", basket);
print basket.get("vat");
1.175
item2.set("value", 10);
item2.set("basket", basket);
print basket.get("net");
20
item2.set("value", 20);
print basket.get("total");
35.25
This represents a fusion of spreadsheet processing with a generic persistent programming model.
matchThere are a number of formula primitives that are listed in the
whitepaper but one worthy
of special mention is the match primitive.
This uses a regular expression to match against a substring, for example if we needed to extract the first and last names of a "full name" value:
g.set("name", "Martyn Cutcher");
g.define("first", "(match '^(\w+)' (-> name))");
g.define("last", "(match '(\w+)$' (-> name))");
g.get("first");
'Martyn'
g.get("last");
'Cutcher'