GolfScript

From Esolang
Jump to navigation Jump to search

GolfScript is a concatenative programming language embedded on top of Ruby, designed to allow very short programs to be written, in order to win code-golf contests. It supports a range of datatypes including arbitrary precision integers, and a wider range of standard operations than many other esoteric programming languages.

Overview

A GolfScript program is a list of items: integers, lists, strings, blocks, variables, and variable assignments. Integers, when encountered, are simply pushed onto the stack. Lists, strings, and blocks behave similarly. Variables are also pushed onto the stack, except when the variable contains a block. If that happens, the block is executed. When a variable assignment is encountered, the top item on the stack is assigned to the variable, but not popped off the stack.

Syntax and Execution

Lists and blocks are delimited by square brackets and curly brackets, respectively. A block is actually just a string that has special behavior. Variable assignment is done by placing a colon before the variable name. Comments begin with a hash and end at the end of the line. Strings are first evaluated by Ruby, allowing an escape to Ruby expressions and frameworks for those functions not provided by GolfScript, such as floating point and math libraries.

Input and Output

Before a GolfScript program is executed, the input is pushed onto the stack as one long string, and therefore interactive input is impossible. When the program finishes execution, the stack's contents are printed, (apparently) starting from the bottom. There are also some explicit built-in methods of printing.

Built-ins

Most of the golfing power of GolfScript comes from its extensive library of operators. These are actually just variables specially initialized. You can assign values to them if you want. Also, most of the operators are overloaded to provide different results if supplied with different arguments. For example, the asterisk * can mean any of:

  • Multiplication, when supplied with two integers
  • To execute a block a number of times, when supplied with an integer and a block
  • To repeat a string or list a number of times, when supplied with an integer and a string/list
  • To join the elements of a string/list together with another string/list, when supplied with two string/lists
  • To reduce the elements of a string/list to one element, when supplied with a string/list and a block

Coercion

When needed, integers are coerced to arrays/strings/blocks, arrays are coerced to strings/blocks (each element is converted to a string and the results are concatenated together), and strings are coerced to blocks.

List of built-ins

Here is a list of built-ins (currently incomplete), in roughly increasing order of complexity. The arguments describe what types of objects should be on the stack, written bottom to top. A slash means that the arguments are interchangeable. 'List' means arrays or strings; 'sequence' means lists or blocks. This terminology is largely arbitrary.

Name Arguments Description
; any Pop, discard
. any Duplicate on stack
\ any, any Swap top two elements
@ any, any, any Move third element on bottom to top
! any Negation: pushes 1 if argument is 0 or empty string/array/block, 0 otherwise.
` any Converts the element to a string that, if evaluated, returns the original
~ int Bitwise not
string or block Evaluate
array Dump the elements onto the stack
, int Construct an array with elements [0, 1, ..., int - 1]
list Find the length
list, block Filter: select elements that return true when the block is applied to them.
& int, int Bitwise and
seq, seq (coerce) Setwise and
| int, int Bitwise or
seq, seq (coerce) Setwise or
^ int, int Bitwise xor
seq, seq (coerce) Setwise xor
$ int Copy stack: copy the nth element of the stack (after popping the argument) to the top.
list Sort
list, block Sort, according to a mapping
( int Decrement
seq Uncons: push sequence without first item, push first item
) int Increment
seq Uncons from right: push sequence without last item, push last item
+ int, int Add two integers
seq, seq (coerce) Concatenate two sequences
- int, int Subtract
seq, seq (coerce) Setwise difference
* int, int Multiply
int/list Copy the sequence (int) times and concatenate them together.
int/block Execute it (int) times.
list, list Join. Put the elements of the second sequence in between each element of the first sequence and concatenate.
list, block Fold. Reduce. Whatever.
/ int, int Integer division
list, list Split around matches with a second array
block, block Unfold: a while loop where the condition test is applied to the top of stack, and if the check passes the element on top of stack is collected into an array.
list, block Each: execute a block over each element, and push the results.
% int, int Integer modulus
list, list Split around matches like /, but omit empty results
list, int Select elements with index 0 mod int. If the int is negative the result is reversed, so [1 2 3]-1% reverses the array.
list, block Map. Somewhat like Each except the results go in a list.

Examples

99 bottles of beer (considerably golfed)

[296,{3/)}%-1%["No more"]+[" bottles":b]294*[b-1<]2*+[b]+[" of beer on the wall\n".8<"\nTake one down, pass it around\n"+1$n+]99*]zip

Quines: Note that since the stack is output at termination, a program like

5

is a quine (as long as no input is given to it). A more non-cheating example could be

{".~"}.~

How it works: block {".~"} pushes the .~ string when evaluated. It's duplicated (blocks are printed with parentheses) and evaluated.

Random example of the golfing that can be done with this code:

~{..{(h{3^3%}%2,@h{2\-}%\;++}{,}if}:h~2/zip{{"ACB"=}%}%n*\;

Computational class

GolfScript is Turing-complete, as it can be shown to be computationally equivalent to Underload: the GolfScript built-ins \.;+{}~ correspond to the TC subset of Underload commands ~:!*()^.

External resources