GML

From Esolang
Jump to navigation Jump to search
This article is not detailed enough and needs to be expanded. Please help us by adding some more information.
Not to be confused with Game Maker Language, a non-esoteric language developed by Yo Yo Games Ltd.

GML is the programming language defined for ICFP contest 2000. The goal of the contest is to implement a ray tracer. The GML language is thus used to describe a scene as input to the raytracer. The description of the language is available in HTML, PDF and postscript format.

GML is a simple pure functional language with syntax somewhat similar to postscript. It has an argument stack and an implicit execution stack. It has lambda syntax that creates functions with read-only variables bound to names. Types of values supported are: boolean, integer, floating point number, point (triples of floats), read-only array containing arbitrary values, function (closure), object, light.

The objects are built using constructive solid geometry. The base objects are sphere, cube, cylinder, plane. The texture of a base object is defined by a "surface function", a GML function that takes surface coordinates as input and returns the color and texture properties at that point of the surface. Objects can be transformed and combined with union, intersection and difference operators. GML has an operator to render a ray-traced image from objects and lights, so a single program may generate any number of images by calling the operator in a loop.

Concatenative calculus as a special case

A very small subset of GML features happens to implement Concatenative calculus / Joy.

Joy is the stack-based analog of untyped lambda calculus. That is, both lambda-calculus and Joy are simple prototypes of an untyped language where every value is a function, and have single-argument lambda abstractions with lexically local bindings. Lambda calculus functions are pure side-effectless. In contrast, Joy functions are allowed the side effect of modifying (a top slice of) the argument stack, where calling a lambda abstraction pops an argument from that same stack and binds it to a name.

The following table shows how to translate Joy into GML. The first four rows show how to translate to GML in general. The next rows are specific functions, of which the first six is a combinator basis for Joy that both Underload and Mlatu chose as their primitives.

Underload mlatu Joy [1] (with combinators) Joy (with lambdas) GML
( ( [ [ {
) ) ] ] }
not representable not representable [X] (X is any identifier) X
not representable not representable X (X is any identifier) X apply
not representable not representable X\ (X is any identifer) /X
: + dup X\ [X] [X] /X X X
! - zap X\ /X
a > unit X\ X /X { X }
~ ~ swap Y\ X\ [X] [Y] /Y /X Y X
^ < i X\ X apply
* , cat Y\ X\ [X Y] /Y /X { X apply Y apply }
~a~* ~>~, cons Y\ X\ [[Y] X] /Y /X { Y X apply }
~a*^ ~>,< dip Y\ X\ X [Y] /Y /X X apply Y

Joy brackets and concatenation translate directly to GML brackets and concatenation. However, there is a difference between Joy lambda abstractions and GML bindings: when a Joy expression mentions a bound identifier, it calls it immediately, whereas GML just pushes it to the stack. Thus you need to translate any Joy identifier into the same GML identifier followed by `apply`. These translations work for any suffix of a Joy program with balanced brackets, even if it has unbound variables. To translate a whole Joy program, translate the contents of each bracketed expression in a leaf-first order, and translate each bracketed expression from right to left.

This is interesting because GML (2000) appears to predate Joy (2001) and the article about concatenative calculus (2002).