Skip navigation

Category Archives: Code and Natural Language

In my last comment I suggested that code, as a language system, may offer greater possibility for logic/narrative integration than might be possible in a “purer” system, such as natural or mathematical language. I guess I should probably expand upon this reckless and highly undisciplined conjecture.

I’ll begin with the very true statement:
“I love to go ice skating”

Permuting the word order some, we get:

“To go Ice skating I love”
“Ice skating I love to go”
“Love to go I ice skating”
“Love ice skating to go I”
“Ice skating to go I love”

Somehow the literal meaning of the original statement seems to remain fairly stable in the permuted variations (even without the aid of explicit syntax.) There are of course subtle shifts in expressive/poetic (connotative) meaning, which I‘ll leave for others to explain. Natural language seems especially suited to this type of fuzziness, allowing for amazing structural variations, without the (complete) loss of literal meaning. In mathematics, some similar flexibility exists, specifically through the commutative property:

45 + 65 + 193 + 200 = 503
65 + 45 + 200 + 193 = 503
200 + 193 + 65 + 43 = 503

50 x 20 x 2 = 2000
20 x 2 x 50 = 2000
2 x 50 x 20 = 2000

Using only the addition or multiplication operators in an expression, operand order doesn’t alter the evaluated value; nor does it impact expressive value. Mathematical language structures were obviously not designed to connote, but rather to definitively denote. For a simple visual explanation of commutativity. Beyond the commutative property of addition and multiplication, operand order usually alters an expression’s value:

50 – 20 x 2 = 10
50 x 2 – 20 = 80
(remember we evaluate multiplication before addition.)

In most instances, changes to operand order within expressions, as well as associative groupings (e.g. 2+3 – 6 x 5 = 30, (2+3 – 6) x 5 = -5), dramatically impact value.
(stuff between parentheses are always evaluated 1st.)

Both natural language and mathematical language are functionally efficient systems. Using the former, I can say “I love you” to my parents, grandparents, siblings, spouse, children, etc and each will take away a different meaning from the statement. The fuzziness provides utility along with the possibility for semantic expansion (my son can learn to love his pet crayfish.)
Using mathematical language, an engineer can calculate the tensile stress of an aluminum wing and communicate this value with absolute precision, without the risk of multiple interpretations–which has some benefit when you’re flying 5 miles over the Atlantic at 600 MPH.

Both natural and mathematical language systems are absolutely fundamental and at the core of, well everything; yet, they seem diametrically opposed (with regard to their defining strengths: fuzziness vs. precision.) I would also (very very politically incorrectly) argue, based on personal experiences working with both Computer Scientists/mathematicians and Artists/”Humanitists”, that the 2 language systems seem to inculcate a bias within their most ardent practitioners. I see this bias also express itself within the digital media classroom, where the majority of my students (upon entering my class) define themselves either as creative or analytical.

It is this divide, between the mutable fuzziness of natural language and the rigid precision of mathematical language, that I’d like to try to put together in a discussion on code, as a potentially integrating language system. However, as this post has already gone on far too long, I will only discuss a few procedurally based code structures. In a later post, I also plan to look at some object-oriented constructs. The code examples to follow will run in the latest version of Processing. If you haven’t checked out Processing yet I highly recommend it; although, I’m somewhat biased.

Variables:
Variables symbolically link a word (identifier) with a stored value (either directly or indirectly).
VariableName = variableValue

There are some rules defining legal identifiers, but essentially any word is valid. Besides an identifier, variables (within Processing and many other languages) are declared of a specific datatype. The datatype limits the type of data that may be associated with the identifier. Some common predefined datatypes include: int, float, String and color.
The complete declaration of a variable:
datatype VariableName = variableValue

Declared variables, as their name implies, may be assigned new values (of their declared datatype.) It is also possible, but outside of the scope of this post, to even create new custom datatypes.

Below are 5 complete and legal variable declarations, followed by a legal reassignment.
int daysOfTheWeek = 7;
int currentAge = 40;
float bodyHeat = 98.6;
String name = “ira”;
color warmth = 0xFF772A;

legal reassignment:
warmth = 0xEE0012;

In each of the statements, the initial term is the declared datatype, followed by a unique identifier, the assignment operator (“=”) and an assigned value. Each expression is terminated by a semi-colon. Variable declarations occur from right to left. So the first declaration above reads: the value 7 is assigned to the identifier daysOfTheWeek. It is a convention to capitalize the initial letter of compound identifier names-for readability.
Below are 2 new additional legal assignments, followed by 2 illegal ones.

Legal:
daysOfTheWeek = 2;
currentAge = daysOfTheWeek;

Illegal:
Warmth = bodyHeat;
currentAge = “forty”;

The initial 2 assignments meet the requirements of assigning the correct types of data to the respective variables. The 2nd statement, which might look odd to non-coders, is perfectly legal as the variable on the right (daysOfTheWeek) is 1st evaluated to 2, prior to being assigned to the variable currentAge.

The 3rd assignment statement (Warmth = bodyHeat;) is illegal because the datatypes of the variables do not match (color vs. float). Although interestingly, the assignment statement, vis-à-vis a natural level reading, seems semantically sound–body heat would generate warmth. The 4th expression is also illegal because of another datatype mismatch.

It seems that this type of assignment syntax offers interesting potential for a multi-level reading of the code, with a (natural language) narrative level (“supertext”) above a (mathematical language) logical execution level. And as was illustrated in the 3rd assignment expression above (Warmth = bodyHeat;), there can exist an interesting tension between the 2 readings.

The variable is the most basic and fundamental code structure, yet even simple assignment operations seem to illustrate an integration of natural and mathematical language systems (fuzziness and precision). Another common code structure that offers a more interesting, (or at least more fun) example of this integration is the random number generator, which we’ll look at with a visual example.

Above I tried to illustrate the fuzziness of a word like “love”, simply to emphasize the connotative range of natural language. Thus the 2 statements:
I love my ice skates
I love my mother
although structurally similar are obviously not semantically similar (or shouldn’t be ;-))

In contrast, here’s an algorithm to generate a 3-sided polygon (yes, it’s also a triangle), centered at coordinate (200, 200) with a radius of 150. Below the algorithm is some processing code that implements the algorithm. To run the code: launch Processing and paste the code into the text editor, and then press run (top left right-facing arrow) or you can use a shortcut: (OS X) command + r or (Win) control + r.

Algorithm:
Loop 3 times:
Set x = 200 + cosine(theta) * 150
Set y = 200 + sine(theta) * 150
Plot (x, y)
Increment theta by 360/3

Processing implementation:
void setup(){
 size(400, 400);
 background(255);
 float angle = 30;
 beginShape();
 for (int i =0; i<3; i++){
  float x = 200 + cos(radians(angle))*150;
  float y = 200 + sin(radians(angle))*150;
  vertex(x, y);
  angle += 360/3;
 }
 endShape();
}

The algorithm, as it is currently written, will always generate a 3-sided poly, with a radius of 150 & center point at 200, 200 (kinda boring.) Normally, we would want to functionalize this type of algorithm to at least allow any n-sided polygon to be generated and also provide parameters to control the poly’s center point and radius.

Here’s a more generalized poly algorithm:
Loop n times:
Set x = circle center along x + cosine(theta) * circle radius
Set y = circle center along y + sine(theta) * circle radius
Plot (x, y)
Increment theta by 360/n

Processing implementation:
void setup(){
 size(400, 400);
 background(255);
// generates a hexagon
 createPoly(6, 75, 200, 230);
}

void createPoly(int vertices, float radius, float centerX, float centerY) {
 float angle = 30;
 beginShape();
 for (int i=0; i<vertices; i++){
  float x = centerX + cos(radians(angle))*radius;
  float y = centerY + sin(radians(angle))*radius;
  vertex(x, y);
  angle += 360/vertices;
 }
 endShape();
}

This is an improvement, but still a far more rigid structure than our love example. Finally, we can add randomization into the function and even the function call to generate a fuzzy implementation of a precise polygon creation machine. I’ll skip the algorithm and just include a Processing implementation:

void setup(){
 size(400, 400);
 background(255);
 noStroke();
 int polys = int(random(1, 20));
 for (int i=0; i<polys; i++){
  createPoly(10, 200, width/2, height/2, 70);
  fill(random(255), 100);
 }
}

void createPoly(int vertices, float radius, float centerX, float centerY, float rand) {
 float angle = 30;
 float randvertices = random(3, vertices);
 beginShape();
 for (int i=0; i<randvertices; i++){
  float x = centerX + random(-rand, rand) + cos(radians(angle))*radius +   random(-rand, rand);
  float y = centerY + random(-rand, rand) + sin(radians(angle))*radius +   random(-rand, rand);
  vertex(x, y);
  angle += 360/randvertices;
 }
 endShape();
}

This fuzzy algorithm now begins to generate something which has certain aesthetic attributes, beyond simply being the precise output of a poly creation algorithm.

And with that I’ll put this ridiculously long post to bed.

Advertisements

Hey folks,

All this talk about natural language and code reminds me of the recent release of Inform 7.  Inform itself is a special purpose language specifically geared towards making interactive text games — think Zork, or if you don't know Zork consider it like a MOO, except self-contained, (usually) puzzle oriented, and finite.  At any rate, Informs 1-6 were sort of typical Perl or Python-esque scripting languages, but 7 manages to completely redo the language syntax in a more natural way.   It's worth checking out.  I often thought that if I ever did an introduction to programming languages for non-techies, I'd try to teach Inform 7.

I want to think more superficially than Ira about the relationship between code and natural language, so here is another set of undisciplined leaps (soon to be disciplined, as I slog through Logic & Language ed. by Benthem and Ter Meulen).  Casey Reas iterates the standard line about the difference between code and natural language:

Machine languages are very different from human languages: They are terse, have strict syntactial rules, and small vocabularies.  In contrast, our languages are verbose, ambiguous, and contain huge vocabularies.  ("The Language of Computers," in Creative Code, Maeda).

My own experience in both programming and writing is that, when you are first learning to write them, programs approach natural language in ambiguity and verbosity.  And the same is true of natural language: the more skilled you get, the more you can reduce verbosity and control ambiguity.  Well, you might say, if a person is an unskilled programmer, the program doesn't work.  And natural language DOES?  I remember when I first read an essay by M. H. Abrams attacking J. Hillis Miller: it was written when deconstruction first came on the scene.  Abrams countered Derrida and Miller with "language works!"  I remember thinking to myself, that doesn't really match my daily experience.  It works sometimes a lot better than others — and that's just at the level of passing information — never mind sincerity, authenticity, effectivity.

But the breakdowns in programming and natural language differ.  When your program is syntactially ill-formed, it works not at all, whereas something happens when you write bad sentences; it just may not be what you want to have happen.  Why?

Reas goes on to say that newer programming languages are "compromises" between machine and natural languages, and the XSL I use, which is very Englishy because XML-based, works all the time with ambiguous rules: everytime I run one particular set of transfroms, I get forty or fifty warnings about ambiguous rules.  Ambiguity will simply cause it to not run the same way each time.  But in natural language, ambiguity is different.  Certain kinds of ambiguity a writer wants absolutely to eliminate, the ambiguity that comes from confusion.  But other kinds are cultivated by writers, and there is one fundamental kind of ambiguity that natural languages have: no sentence ever — ever — does only one thing.  It may tell a story, but it is also a move in a game: every story told in every sentence is persuasive, seductive.  There is no grammar without motive (to borrow a title from Kenneth Burke).

The major thinkers who tried to bridge the division between logic and grammar were the logical positivists, Carnap, the Vienna Circle, and Wittgenstein was one of them.  The early (logical) Wittgenstein attempts to reduce natural language to logical propositions.  The late (grammatical) Wittgenstein adds the game element to linguistic propositions.

But if grammar differs from logic because of motive — desire for a win state — and game rules, can't code come close to natural language?  Making games is one thing you can do with it.  But really to be a natural language, it has to come from the human mouth.  So you have code that a computer takes up and does something with.  As John Simon says, the machine takes the words out of your mouth:

When I describe programming as creative writing, I am thinking beyond the short stories and poems I wrote as a freshman in English class.  The process of coming up with an idea, developing it, and finally sitting down to type it is still the same.  But I consider programming as creative writing for a different reason: When I have finished typing, it is the writing itself that starts to create.  The code becomes a working machine, and it is fascinating to see what it will do.  ("Authorship, Creativity, and Code," in Creative Code, Maeda)

Natural language is like that, too: it takes you up and invents you as you write; it is like a machine.  But at some point your own deeper motives change the rules.  Maybe code will approach natural language as soon as programs can be written that allow the user to make changes in the program.

Ira's last posting appears as a comment — I can't quite get this program to put eveyone on as writers!  But Ira's posting is too important to be hidden in the commentary, so here it is.  Ira writes,

Here’s a rather large and “undisciplined” leap.

Rather than define the blurring with disciplinary-based (and very high-level) binaries: “designer and artist, author and designer…” I’d suggest going a level lower and argue that code (the medium to manipulate electricity) blurs the line separating natural language and mathematical language. This binary seems to be the key dilimiter, dividing not only our brains but our universities and beyond. The binary also seems to subjugate other formal language systems: we define visual or aural language in terms of analytical and/or narrative structures. A work of art reflects this bifurcation-e.g. a geometric 2D pictorial structure anchors an expressive figurative narrative. Integration happens only though explicit organization. Natural language systems seem to sacrifice rigidity for mutability, while mathematical systems employ an opposite strategy.

Code has the potential to be an integrated language system, functioning both as an analytically and narratively expressive medium. So yes, I’d say Cooper may be right.