Motto tutorial
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:
> 3.14159265 PI @
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:
> ["hello, world" .s .c]
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:
> ! hello, world
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