On J.R. Carpenter’s Gorge, Part Two: Choosing the Words


This post is the second in a series on digital literature. I’m dissecting the JavaScript code of “Gorge”, an infinite poem by J.R. Carpenter that riffs on Nick Montfort’s program “Taroko Gorge”.  The first post, which defines “variables”, “strings” and “arrays”, is here.

At the end of the last post, I said that we would continue by looking at how to choose a substring from an array, and what happens from there. In order to understand how the program selects a substring, you have to understand something else first: what a function is, and how it works within a program.

It’s hard to meaningfully define a function in non-technical terms because it is so basic a thing that breaking it down further is difficult; at the same time, too vague a definition will be imprecise and therefore meaningless. The best I can do for you right now is to say that functions are basically chunks of code that, as the name might suggest, do something. When you call a function, you’re invoking the code in it. If similes are your thing, you could say that calling a function is like casting a spell: you can have the spell written down, but it doesn’t do anything until you bring it into existence.

Functions have names, arguments, and bodies. This is probably best illustrated by actual code:

 function rand_range(max) {
   return Math.floor(Math.random() * (max+1));

The name of that function is rand_range, the argument that we pass to it is max, and the second line (beginning with the word return) is the body of the function. It is, in other words, what the function will do, when it is called, with the argument max. max, as you may have guessed by now, is just a variable representing a maximum value. If we say that max is 3, the function will execute with 3 taking max‘s place.

What does that mean, practically speaking? What will the function actually do when called? Its name should give you a clue: looking at something called rand_range, it’s a safe bet that it’ll have something to do with a random number that falls within a predetermined range. Add the fact that the argument has been named max, and you can further guess that the value of max represents the top end of that predetermined range. Now all you have to contend with is Math.floor and Math.random. Math.floor is a function (functions can call each other) that returns the largest integer less than or equal to a given number (in this case, max); Math.random returns a pseudo-random (which is to say, more or less random for most purposes but not strictly random, since that’s pretty hard to achieve) integer between 0 (inclusive) and 1 (exclusive). You can scale that up or down; in the event that max is 3, as I suggested earlier, Math.random returns an integer between 0 and 3, not including 3. This is why the function includes (max + 1), which extends our range by 1, allowing us to include 3.

The next function is called choose. It exists in order to produce a random selection from the arrays that we discussed earlier, the ones like above (“appetite, brain, craving, desire”), below (“aroma, bladder, blood vessel, bowl”), and trans (“agitate, attract, bite, boil”). choose looks like this:

 function choose(array){
   return array[rand_range(array.length-1)];

When you insert the name of an array—let’s say above[rand_range(array.length-1)] selects a random value from that array. (The -1 bit is there because the first thing in an array is denoted Thing 0. Computers like to start counting at 0. So -1 just means that you get the whole range of the array from the first (zeroth?) item to the last.) Then return array returns the index that’s been selected. So if we were to do this with above, the index might be, e.g., 3, which would return ‘digestive juice’ (since we’re counting from 0, remember!)

The next function is where we start to get into the actual construction of the poem, and it’s followed by two other functions that are very similar. These functions haven’t been renamed since their inception as part of Taroko Gorge, so they may at first glance appear irrelevant to the content of Gorge, but they’re doing the right things. There’s a section in the middle of this first function that doesn’t work in Gorge, which you’ll probably be able to spot straight away. It doesn’t do anything bad; it just doesn’t get evaluated.

 function path() {
 var p=rand_range(1);
 var words=choose(above);
 if ((words=='forest')&&(rand_range(3)==1)){
   words='monkeys '+choose(trans);
 } else {
   words+=s[p]+' '+choose(trans)+s[(p+1)%2];
 words+=' the '+choose(below)+choose(s)+'.';
 return words;

And breathe.

var p is defined as rand_range(1), which we know means “a random whole number between 0 and 1”. Practically speaking, that means “either 0 or 1”. We don’t know what we’ll be doing with var p yet, so we’ll just put that away for later use.

var words=choose(above), as we know from our adventures with choose(array) previously, means that words is set to a random selection from the list of words in the array above.

The if statement says that if the value of words happens to be “forest”, and if the rand_range value is 1 (with the max value defined as 3, so the value could be 0, 1, 2 or 3), then “forest” will be replaced with the word “monkeys” and a random selection from the transarray. Since we don’t have the word “forest” in any of our arrays, this piece of code will actually never be used. It’s a leftover from Montfort’s original version.

else means “otherwise”, so this is where we can start paying attention again: if the conditions of the if statement are not met (and they won’t be), this is what will happen next.

words+=s[p] is a random pluralizer. It takes a var from earlier up in the program, which I realize now I may have skated over somewhat in the first post. This is s, which is defined as 's,'.split(','). What this means is that s is actually another array, split on its comma, so that the array consists of the letter ‘s’ and nothing, known in programming as ‘the empty string’. Therefore, words+=s[p] means that when p=0, s will be added on to the end of whatever value we got from words. (words+=s[p] is a short-hand for words=words+s[p]. “Adding” a string means that it is glued on to the end of whatever comes before.) As we start counting from 0, that means a letter ‘s’ will be added, making the word plural. When p is 1, the second element of the array s will be added to the end of words, which in this case means nothing at all.

After this will come a space (signified by ' '), no matter whether the value of var words has been pluralized or not. Then a word will be selected from the trans array, which will be pluralized half of the time. This is signified by (p+1) % 2, where % means “the remainder after division by”. Cast your mind back to elemento-primary school! When p is 0, we get 0+1, which is 1, and the remainder of 1 divided by 2 is 1. We’ll add element 1 of array s again, which is empty string. When p is 1, we get 1+1, which is 2, and the remainder of 2 divided by 2 is 0, so we’ll append the first element of array s (remember, the first element is element 0!), which is the letter ‘s’.

The final section has the addition of the word ‘the’ to whatever comes out of words, a random selection from the array below, a random selection from the array s (another choice between pluralizing or not), and the addition of a full stop. return words is the piece of code that will actually return the value for function path(), when it’s called.

More next time, including a couple of other functions that select words from arrays using different criteria, and the beginnings of how the program fits all of these functions together to produce the poem itself.


On J.R. Carpenter’s “Gorge”, Part One: String Theory


There’s this thing called digital literature. To those of us with a disposition to love physical books, their material essences, the phrase can be alienating, disturbing even. It makes me think of some immense ethereal database, to which novels and poems and plays can be hooked and uploaded, a Matrix of the creative mind. It doesn’t, in those terms, sound particularly appealing, but rather like a vast, crammed forest. It sounds like somewhere you could get lost—not in the exciting, carefree, sight-seeing way, but more in the “oh God this industrial wasteland is nowhere near our hotel and also it’s raining” sort of way.

Fight this fear. Digital lit is really, really neat, not least because it’s so much less interested in uploading Madame Bovary to the Cloud than it is in finding out completely new ways of creating things with words, using technology and programming languages as tools to assist in the endeavour. I’m going to be writing a series of posts exploring one instance of digital literature, breaking it down into its source code, looking at that code, assessing how it works, and finally deciding what it’s worth as literature. If you have never seen computer code in your life before, I urge you not to navigate away immediately; until this summer, I’d never had a proper look either, so I promise you that everything will be explained for the layman, clearly and accurately. (I live with a real live computer scientist, who checks all of these posts for accuracy.) Plus, the possibilities for what you can do with code are literally infinite—it’s expressed in languages just like literature is—so it’s worth your while to know something about what can be done with it.

In 2009, Nick Montfort wrote a program that created a neverending poem called “Taroko Gorge“. (Do you see what I mean about these things being really neat? A neverending poem! Holy shit!) You might think that this would require a great deal of complicated and arcane mathematics and large word banks upon which to draw—not a bit of it. Such are the joys of combinatorics that you don’t actually need very many resources in order to create a large number of variations. It’s likely that, given some complicated and arcane mathematics and large word banks, you could create a more complex, nuanced and interesting neverending poem, and this is a notion worth exploring, but we’ll get to that later. For now, let’s look at the code.

The code I am going to look at here actually belongs to an adaptation of Montfort’s program by a poet and programmer called J.R. Carpenter. (She’s commented on this post, so check out her comment below!) I came across it while looking at a zine called Hack Circus, which I’d recommend wholeheartedly. They describe themselves as an artistic collective interested in “the entertaining and engaging side of inventive thought, whether that manifests physically with wires and batteries, or conceptually in artistic or philosophical ways”—or, as their website tagline succinctly puts it, “fantasy technology and everyday magic.” It’s a playground for the imagination; every article is a jumping-off point for something fascinating and bizarre.

Carpenter calls her iteration of the work “Gorge“. You’ll realise why when we start to look at her inputs: the poem that “Gorge” produces is, yes, about the body and its processes, while the poem generated by “Taroko Gorge” is about the natural world and has a serene, secluded feel to it. But that’s nothing to do with the structures of either poem; it’s entirely down to the words. If you look at their skeletons, these two poems are built the same way, and I’m just not sure that structure should be irrelevant to two poems with completely different emphases. It’s as though Allen Ginsberg’s “Howl” and Marlowe’s “Come live with me and be my love” were written in the same meter and idiom.

On the other hand, both “Leda and the Swan” and “The Windhover” are sonnets about birds, and they still manage to capture their own very different essences in similar forms. (On the other other hand, “The Windhover” is extremely cavalier about meter. You could keep having this argument forever.)

So, Carpenter’s code starts like this:

var t = 0;
var n = 0;
var paths = 0;
var above = 'appetite, brain, craving, desire, digestive juice, enzyme, gaze, glaze, gorge, gullet, head, incisor, intellect, jaw, knowledge, language, maw, mandible, mind, molar, muscle, mouth, nose, sight, smell, spit, sweat, spirit, thirst, throat'.split (',');
var below = 'aroma, bladder, blood vessel, bowl, bowel, crust, dip, dressing, film, gut, lip, lower lip [etc etc]'.split (',');
var trans = 'agitate, attract, bite, boil, braise [etc]'.split (',');
var imper = 'become, confuse, cut, decant, enter [etc]'.split (',');
imper = imper.split (',');
var intrans = 'absorb, age, assimilate, balance [etc]'.split (',');
var s = 's,'.split (',');
var texture = 'acrid, barely perceptible, cautious [etc]'.split (',');

In JavaScript, the programming language that this code is written in, var introduces a variable. A variable in programming is just a thing that gets assigned a value. We’ll worry about var t, var n, and var paths later; we don’t have enough information about them right now to assess them meaningfully, other than to note that they have all been assigned a value of 0. What we do have is a large amount of information about the other variables, all of which seem to have been assigned multiple different values. But if you scroll to the right, you’ll see that the whole shebang—all of the words associated with, say, var above—are within one set of quotation marks. And what that makes them is one value, because they’re a string. A string is everything inside a set of quotation marks, which all gets lumped together and treated as one. So, for instance, ‘appetite, brain, craving, desire’: the program will treat that list of adjectives as one value for our variable, unless told otherwise. What tells it otherwise is the piece at the end of each line, .split (',').

What .split (',') does is split up the string (hence the name; everything in programming has or should have an eminently reasonable name) into an array of substrings. The advantage of writing like this is that it prevents the programmer from having to type out a whole bunch of quotation marks (like, ‘appetite’, ‘brain’, ‘craving’, ‘desire’ and so on). The advantage of making an array of substrings, instead of one massive string, is that now, in theory, we can choose any one of those substrings to be the value of our variable above.

Next up: How we choose a substring, and what happens after that.