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] /boston/2006/03/13/plotdriver.scm