CatCon
A (toy) concatenative language built in Ruby. It is stack based
so named variables are not available (though named functions are, though
functions which return a signle value are).
25 10 * 50 + print
;=> 300
; in other languages it's probably written like this
; print((25 * 10) + 50)
25 10 * 50 + 300 eq? print
;=> true
; as 300 == 300
would print true as 300 is equal (#eq?) to 300. To really understand what is happening
take it step by step.
[] ; program begins with empty stack
[25] ; 25 is pushed on to the stack
[25, 10] ; 10 is pushed on
[250] ; #* takes top two items on the stack and multiplies them
[250, 50] ; 50 is pushed on
[300] ; #+ takes the top two items and adds them together
[300, 300] ; 300 is pushed on
[true] ; #eq? takes the top two items and checks whether they are equal
;=> true ; #print takes the top item and prints it to STDERR
Defining Functions
To define functions use the #define function.
"sq" [
dup *
] define
5 sq print
;=> 25
; [5] ; 5 pushed on to the stack
; [5, 5] ; #dup adds a copy of the top item to the top of the stack
; [25] ; #* takes the top two items and multiplies them
Note that to name the function a string was used, not an identifier as that
would have meant the function #sq was called, which didn't exist until it was
#defined
Flow Control
The #if function takes the top item from the stack and tests whether it is true or
false, if true it evaluates the second item on the stack, if false it evaluates
the third item.
true
["It was false" print]
["It was true" print]
ifelse
;=> "It was true"
;
; [true]
; [true, ["It was false", print]]
; [true, ["It was false", print], ["It was true", print]]
300 25 10 * 50 + eq?
["300 = 300" print] if
; [300]
; [25, 300] ; #*
; [250, 300]
; [300, 300] ; #+
; [true] ; #eq?
; [["300 = 300", print], true]
; [[], ["300 = 300", print], true]
; ["300 = 300"]
Delayed Evaluation
Wrapping a set of instructions with square brackets ([ and ]) prevents them from
being evaluated immediately. These are used for certain functions, #if and #define
for instance, to execute a statement use the #call function:
1 2 [swap 1 +] call eq?
; [1]
; [2, 1]
; [[swap, 1, +], 2, 1]
; [1, 2] -> [1, 1, 2] -> [2, 2]
; [true]
For a single function it is a bit of a pain having to wrap it in [ and ] so
a shortcut is available, prefix the function name with a semi-colon,
1 :inc 5 times
; [1]
; [1, [inc]]
; [1, [inc], 5]
; [6]