    Appendix: The Nickle Tour

Material in typewriter font is taken from a Nickle interactive session. Material in italics is commentary.

\$ nickle
The obvious calculations work, including fancy operators and arbitrary precision.
> 1 + 1
2
> (2 ** 4)!
20922789888000
Rationals are representend exactly, but printed in decimal. Integer division with // is different from rational division.
> 1 / 3
0.{3}
> . * 3
1
> 1 // 3
0
Expected conveniences, like the value . denoting the last value printed, work. Implicit declarations work at top level, as do explicit typed declarations. Using a statement form at top level results in no value being printed.
> x = .
0
> int y = x;
C-style statements can be typed at the command line. The + prompt denotes an incomplete statement.
> for (int i = 1; i <= 9; i += 2)
+   x += i;
> x
25
Exact integer square roots will be represented by integers. For irrational roots, a 256 bit floating point representation is used; the printed representation is indistinguishable.
> xsqrt = sqrt(x)
5
> sqrt(2)
1.4142135623730
> . * .
2
> sqrt(5)
2.2360679774997
> . * .
4.9999999999999
Functions may be typed at the command line. Argument and result types are optional. This function returns nonsense for non-integers.
> function sqr(x) {
+   auto s = 0;
+   for (int i = 1;
+        i < 2 * x + 1;
+        i += 2)
+     s += i;
+   return s;
+ }
> sqr(5)
25
> sqr(5.1)
36
Functions are first-class: untyped functions can be assigned to statically typed function variables.
> int(int) isqr = sqr;
> isqr(5)
25
> isqr(5.1)
->     isqr ((51/10))
Incompatible types 'int', 'rational'
argument 0
Operators try to behave properly in as many cases as possible.
> 5.1 ** 2
26.01
> -5.1 ** 2
26.01
> -5.1 ** 3
-132.651
> -5.1 ** 3.1
Unhandled exception "invalid_argument"
at /usr/local/share/nickle/math.5c:196
"log: must be positive"
0
(-51/10)
> quit
For reasonable sized chunks of code, it is normal to use a separate text file.
\$ cat > stack.5c
namespace Stack {
typedef frame;
typedef struct{
poly val;
*frame next;
} frame;
public typedef * *frame stack;
public exception stack_underflow();

public stack function
new() {
return reference(0);
}

public void function
push(stack s, poly xval) {
*s = reference((frame){
next = *s,
val = xval
});
}

public poly function
pop(stack s) {
if (*s == 0)
raise stack_underflow();
poly xval = (*s)->val;
*s = (*s)->next;
return xval;
}
}
^D
Here is the Stack ADT in action.
\$ nickle
> print Stack
namespace Stack {
public typedef **frame stack;
public stack function new ();
public void function
push (stack s, xval);
public function pop (stack s);
}
> import Stack;
> stack s = new()
&0
> push(s, "x")
> push(s, 3)
> pop(s)
3
> pop(s)
"x"
Uncaught exceptions lead to the debugger.
> pop(s)
Unhandled exception "stack_underflow"
at stack.5c:23
- trace
raise stack_underflow ();
pop (&0)
pop (s)
- s
&0
- done
> quit
\$   