GOOS is a macro language for GOAL. It is a separate language. Files written in GOAL end in
.gc and files written in GOOS end in
.gs. The REPL will display a
goos> prompt for GOOS and
gc > for GOAL.
There is a special namespace shared between GOOS and GOAL containing the names of the macros (written in GOOS) which can be used in GOAL code.
To access a GOOS REPL, run
(goos) from the
gc > prompt.
This document assumes some familiarity with the Scheme programming language. It's recommended to read a bit about Scheme first.
Note that most Scheme things will work in GOOS, with the following exceptions:
- Scheme supports fractions, GOOS does not (it has separate integer/floating point types)
- The short form for defining functions is
(desfun function-name (arguments) body...)
- GOOS does not have tail call optimization and prefers looping to recursion (there is a
Most forms in Scheme have a name, and list of arguments. Like:
(my-operation first-argument second-argument ...)
Usually, each argument is evaluated, then passed to the operation, and the resulting value is returned. However, there are cases where not all arguments are evaluated. For example:
In this case, only one of
(do-y) are executed. This doesn't follow the pattern of "evaluate all arguments...", so it is a SPECIAL FORM. It's not possible for a function call to be a special form - GOOS will automatically evaluate all arguments. It is possible to build macros which act like special forms. There are some special forms built-in to the GOOS interpreter, which are documented in this section.
This is used to define a value in the current lexical environment. For example:
(define x 10)
x as a variable equal to
10 in the inner-most lexical environment. (Note, I'm not sure this is actually how Scheme works)
There is an optional keyword argument to pick the environment for definition, but this is used rarely. The only named environments are:
(define :env *global-env* x 10)
x in the global (outer-most) environment, regardless of where the
define is written.
This form simply returns its argument without evaluating it. There's a reader shortcut for this:
;; reader shortcut
'x ;; same as (quote x)
It's often used to get a symbol, but you can quote complex things like lists, pairs, and arrays.
goos> (cdr '(1 . 2))
goos> (cdr '(1 2))
goos> '#(1 2 3)
#(1 2 3)
Set is used to search for a variable in the enclosing environments, then set it to a value.
(set! x (+ 1 2))
will set the lexically closest
x to 3. It's an error if there's no variable named
x in an enclosing scope.
See any Lisp/Scheme tutorial for a good explanation of
Note that GOOS has some extensions for arguments. You can have a "rest" argument at the end, like this:
(lambda (a b &rest c) ...) ;; c is the rest arg
(lambda (&rest a) ...) ;; a is the rest
The rest argument will contain a list of all extra arguments passed to the function. If there are no extra arguments, the rest argument will be the empty list.
There are also keyword arguments, which contain a
&key before the argument name.
(lambda (a b &key c) ...) ;; b is a keyword argument, a and c are not.
(lambda (&key a &key b) ...) ;; a and b are keyword arguments
These keyword arguments must be specified by name. So to call the two functions above:
(f 1 2 :c 3) ;; a = 1, b = 2, c = 3
(f :a 1 : b 2) ;; a = 1, b = 2
Note that it is not required to put keyword arguments last, but it is a good idea to do it for clarity.
There are also keyword default arguments, which are like keyword arguments, but can be omitted from the call. In this case a default value is used instead.
(lambda (&key (c 12)) ...)
(f :c 2) ;; c = 2
(f) ;; c = 12
The order of argument evaluation is:
- All "normal" arguments, in the order they appear
- All keyword/keyword default arguments, in alphabetical order
- It is not recommended to rely on this
- All rest arguments, in the order they appear
cond. If no cases matches and there is no
else isn't implement, just use
#t instead for now.
or. If nothing is truthy,
#f. Otherwise returns first truthy.
or. If not all truthy,
#f. Otherwise returns last truthy.
Kind of like
lambda, but for a macro.
- Evaluate the arguments
- Evaluate the body
- Don't evaluate the arguments
- Evaluate the body
- Evaluate that again
You can think about a
lambda like a "normal" function, and a
macro as a function that receive code as arguments (as opposed to values), and produces code as an output, which is then evaluated.
See any Lisp/Scheme tutorial. GOOS supports:
Special while loop form for GOOS.
(while condition body...)
To add together
(define count 0)
(define sum 0)
(while (< count 100)
(set! sum (+ sum count))
(set! count (+ count 1))
Not Special Built-In Forms
TODO - None at this time
define form accepts an environment for definition. For example:
(define :env *goal-env* x 10)
x in the
*goal-env*. Any macros defined in the
*goal-env* can be used as macros from within GOAL code.
Things that aren't macros in the
*goal-env* cannot be accessed.