Making sense of IvoryScript values
Values provide information. Integers provide quantities for calculation, characters and strings express text, and truth values provide the basis for logical reasoning. Such values form some of the fundamentals of a programming language.
A value is denoted by some combination of symbols, or tokens. For example, in IvoryScript:
#!42
#!'a'
#!"forty two"
#!True
denote an integer, a character, a string and a truth value respectively.
The language makes a specific distinction between a value and an expression with a potential value. For example:
42
does not denote the integer value forty-two in IvoryScript. It is an integer expression constant. This is perhaps easier to understand with an expression like (7 * 6) - no assumption is made that its value is 42.
There is obviously a design choice as to whether a constant
such as 42 should denote an integer value or an
integer expression value. The choice of the latter for
IvoryScript was for conformity with other expression forms.
Thus:
#!42
#!(7 * 6)
both denote the integer value forty-two.
Many different forms may denote the same value. For example:
#42
#!42
!42
#!(7 * 6)
The first #42 is known as a literal constant. It
has identical meaning to #!42 — nothing is implied
by the difference, which allows for more consistent terminology.
This is more than a distinction in notation. Expressions are
first-class values in IvoryScript. They may be associated with
names, passed as arguments, returned from functions, contained
within other values, copied or persisted irrespective of their
potential value.
Other expression values
Constants are only one form of expression value. Other source
expression forms include name occurrences, function
applications, lambda expressions, let expressions,
case expressions and conditionals.
A name occurrence:
x
is an expression whose value is that associated with the name in a particular scope.
Function applications (without brackets in IvoryScript) are also expressions:
f x
f x y
an expression whose reduced value is determined by the function and its arguments. That value may also be an expression value.
Lambda expressions provide function values:
\x -> #!(cos x)
Perhaps surprisingly, a lambda function is also an expression
value. This provides consistency with a function application
where a function is returned - analogous with an expression
constant. For example, \x -> #!(cos x) and
trigFn #"cos" where:
trigFn f =
#!(case f of {
"sin" -> sin;
"cos" -> cos;
...
})
A let expression associates values with names
for use within another expression:
let {
x = 7;
y = 6
} in
#!(mulInt x y)
Selection between expression values may be written using
case:
case x of {
0 -> e1;
1 -> e2;
otherwise -> eDefault
}
or, where appropriate, using conditional syntax:
if condition then e1 else e2
These forms describe values and relationships between values.
More elaborate expressions follow the same principle. For
example, the value corresponding to 1 + √2 can be
denoted explicitly as:
#!(addDouble #1.0 #!(sqrt #!(fromIntDouble #2)))
This can also be expressed more simply as:
1.0 + (sqrt 2)
The relationship between these forms will be considered separately.
Expressions therefore need not be regarded as computations awaiting execution: they are values in their own right. An integer is a value; an integer expression is a different value.