|#lang lindenmayer/simple||package: lindenmayer|
The lindenmayer/simple language is a trimmed down version of #lang lindenmayer that supports only a single Lindenmayer system and does not support parametric or conditional Lindenmayer systems, nor does it support interoperability with other languages. It is intended to be a digestible example of a language implemented with #lang.
Here is one example use of the language.
|## axiom ##|
|## rules ##|
|A -> AB|
|B -> A|
|## variables ##|
When it is run, it produces the output:
There are three main pieces to the implementation of the language: the parser, which translates the notations above into a use of lindenmayer-system, the macros that translate that into a call to the run-lindenmayer function, and then that function itself.
|(require lindenmayer/simple/parse)||package: lindenmayer|
'(module name racket/base
(define (finish val) (newline))
(define (A value) (display 'A))
(define (B value) (display 'B))
(A -> A B)
(B -> A)))
(lindenmayer-system start-expr finish-expr iterations-expr axiom rule ...)
axiom = (id ...) rule = (id -> id ...) | (id → id ...)
start-expr : any/c
finish-expr : (-> any/c any/c)
iterations-expr : natural?
This form is implemented by compiling into a call to run-lindenmayer.
|(require lindenmayer/simple/run)||package: lindenmayer|
This module is implemented in Typed Racket, so its inputs are described as types. (Typed Racket can be called from Racket, and vice-versa.)
#:extra-constructor-name make-cell #:mutable) item : (Lindenmayer-Dag α)
The axiom is expected to be an interior node whose children are all leaves (and thus contain procedures). The nts and the rules arguments are expected to have the same length; each pair of elements (one from each argument) together represent a single rule. When performing a rewriting step, run-lindenmayer replaces each non-terminal by invoking the corresponding element of rules.
The init argument is used after the final Lindenmayer string is constructed. It is passed to the first leaf in the DAG representing the Lindenmayer string and then the result of that procedure is passed to the next, and so on, until the last one, whose result is the result of the entire call to run-lindenmayer
(define (A-proc val) (cons 'A val))
(define (B-proc val) (cons 'B val))
(define A (cell A-proc))
(define B (cell B-proc))
> (reverse (run-lindenmayer 4 (cell (list A)) ; the axiom, as a cell (list A B) ; the non-terminals ; procedures that perform the rule rewrites (list (λ (lst) (list (list-ref lst 0) (list-ref lst 1))) (λ (lst) (list (list-ref lst 0)))) ; the initial value '()))
'(A B A A B A B A)
|(require lindenmayer/simple/lex)||package: lindenmayer|