Motto is a practical syntax weak language in the tradition of Forth
and Lisp.
This post introduces the kernel of Motto where syntax is used only
for identifying literals.
You can evaluate simple program statements in the Motto REPL:
motto v0.0
> "hello, world"
"hello, world"
> ; this is a comment.
> 34 6.23
> #\a #\b #\c ; characters
> #t #f ; boolean
> .s ; show what is on the stack
"hello, world" 34 6.23 #\a #\b #\c #t #f
> .c ; clear the stack.
Values we enter at the REPL is pushed to a data stack which is printed back to the user.
You can also type commands or procedures that does something with the values on the stack.
Procedures leave their result(s) back on the stack. Let us try the built-in arithmetic procedures:
> 4 5 +
9
> 10 *
90
> 45 2 remainder
90 1
> .c
> 45.89 5 /
9.178
> .c
> 943423792472394723947234927 323231313 *
304944111156291662875737288173669151
In short, programming in Motto is based on a simple rule: Push values to the data stack and
issue commands (procedures) that does something with those values.
A basic type in Motto is the symbol. A symbol is the same as a string, but is not enclosed
in double quotes. The following are all valid symbols:
> red green blue |a symbol with spaces|
A symbol is unique within the Motto virtual machine. So it can be used as a descriptive identifier
for a literal. A value on the stack is bound to a symbol so that it can be recalled later using
this descriptive name. The bind procedure (represented by a @) binds a value to a symbol:
Here the value 3.14159265 is bound to the symbol PI. We can use this symbol wherever we need
the value of pi. For example, the following statement calculates the area of a circle with radius
100.897:
> PI 100.897 dup * *
31982.055975130526
The dup procedure duplicates the top of the stack. So the actual code that gets executed here is
3.14159265 100.897 100.897 * *.
Execution can be delayed by enclosing program statements in square brackets. Such suspended pieces of
code are called code blocks:
The above statement creates a code block. If you display the stack now, you can see the compiled
version of this code block sitting on the stack:
> .s
#<$proc #2 env: #f binding-env: #<$env #3 parent: #<$env #4parent: #f definitions: #<table #5>> definitions: #<table #6>> opcode: ((1 . "hello, world") 32 31)>
The bang procedure (represented by !) is used to execute a code block:
Code blocks are first class types like strings and numbers. So they can be bound to symbols.
A code block that is bound to a symbol is known as a procedure. Let us define a procedure
that calculates the area of a circle. This procedure will consume the top value on the stack
and use it as the radius:
> [dup * PI *] area-of-circle @
> 45.78 area-of-circle
6584.17626524826
> .c
> 100.897 area-of-circle
31982.055975130526
> .c
Notice that a procedure is automatically executed by Motto. We need the bang procedure only for
executing unbound code blocks.
In future posts I will cover:
- data types – number, character, boolean, string, list, array, map etc.
- procedural abstractions – recursion, closures.
- dynamically extending the compiler and virtual machine.
Before we conclude, here is a glimpse of the higher-order programming facilities provided by Motto:
> ;computing area of many circles in one go...
> 45.32 12.78 90 78 [area-of-circle] apply
6452.524683657361 513.1113009762599 25446.900465000002 19113.4496826
> ;...add them together...
> [+] reduce
51525.98613223362