* * * * *

               RACTER, generative text and Lisp. Oh my! Part II

I found programming in [DELETED-Lisp-DELETED][DELETED-Scheme-DELETED]guile to
be quite frustrating—partly due to it being an unfamiliar environment to
program in and partly due to not fully understanding the implications of my
design decisions for the generative text platform I'm developing.

Ideally, I wanted something like:

> (define firstname
>   #(
>       "Alice"
>       "Bob"
>       "Carol"
>       "Dave"
>   )
> )
>
> (define lastname
>   #(
>       "Smith"
>       "Jones"
>       "Conner"
>   )
> )
>
> (define heros ;; from scifi.scm from the other day
>   #(
>         "Tim Conway"
>         "Big Bird"
>         "The Fonz"
>         "Wonder Woman"
>         "Kareem Abdul Jabar"
>         "Tom Selleck"
>         "Lucille Ball"
>       #((ref firstname) " " (ref lastname))
>   )
> )
>

Where heros will be one of “Tim Conway” or a generated named like “Carol
Jones.” And it was handling this “second level” of references where I had
difficulty (lots of unbound and/or undefined references—God I can't stand
dynamic languages). I spend hours trying to figure out how to iterate through
an array. I mean, in a C-like language it would be something like:

> for (i = 0 ; i < array.length ; i++)
> {
>   if (typeof(array[i]) == string)
>     result.append(array[i]);
>   else if (typeof(array[i]) == array)
>     result.append(expand_array(array[i]));
> }
>

But [DELETED-Lisp-DELETED][DELETED-Scheme-DELETED]guile is rather lacking in
the loop department; instead you're supposed to use tail recursion [1] or one
of the mapping functions and [DELETED-Lisp-DELETED][DELETED-Scheme-
DELETED]guile's support of arrays isn't quite as dynamic as say, Perl, and
well …

I found the experience rather trying.

But in the end the code turned out to be rather simple. Well, once I “fixed”
the data structures being used:

> (define firstname
>   #(
>       "Alice"
>       "Bob"
>       "Carol"
>       "Dave"
>   )
> )
>
> (define lastname
>   #(
>       "Smith"
>       "Jones"
>       "Conner"
>   )
> )
>
> (define heros ;; from scifi.scm from the other day
>   #(
>         "Tim Conway"
>         "Big Bird"
>         "The Fonz"
>         "Wonder Woman"
>         "Kareem Abdul Jabar"
>         "Tom Selleck"
>         "Lucille Ball"
>       ((ref firstname) " " (ref lastname)) ;; look! a list!  Not an array!
>   )
> )
>
> (define rndstate 0)
> (define refn     array-ref) ;; return an element from an array
>
> ;; need this to get random numbers out of (random)
> (set! rndstate (seed->random-state (current-time)))
>
> (define (nref a) (car (array-dimensions a)))
> (define (ref a)
>   (let
>     ((result (refn a (random (nref a) rndstate))))
>     (cond
>       ((string? result) result)
>       ((list?   result) (eval
>                                 (cons 'string-append result)
>                                 (interaction-environment)
>                         ))
>     )
>   )
> )
>

Now that this is working, adding additional functions and variables should be
straightforward. And today's example is a guile version [2] of my Quick-n-
Dirty B-Movie Plot Generator [3].

[1] http://en.wikipedia.org/wiki/Tail_recursion
[2] gopher://gopher.conman.org/0Phlog:2006/03/13/plotdriver.scm
[3] https://boston.conman.org/cgi-bin/plotdriver.cgi

Email author at [email protected]