Om
A Simple Programming Language
Functions

Each Om program evaluates to a function.

Prefix Notation

Om uses prefix notation: functions read their inputs from the right. Prefix notation has the following advantages over postfix notation typical of concatenative languages:

  • Stack underflows are impossible.
  • Prefix notation more closely models function composition. Instead of storing a data stack in memory, the Om evaluator stores a composed partial function.
  • The evaluator can read, parse and evaluate the input stream in a single pass, sending results to the output stream as soon as they are evaluated. This cannot be done with a postfix, stack-based language because any data on the stack must remain there as it may be needed by a function later.
  • Functions can be optimized to only read into memory the data that is required; stack-based postfix languages have no knowledge of the function to apply until the data is already in memory, on the stack.
  • Incoming data, such as events, become simple to handle at a language level: a program might evaluate to a function that acts as a state machine that processes any additional data appended to the program and transitions to a new state, ready to process new data.
  • An integrated development environment can provide hints to the user about the data that is expected by a function.

Input and Output

A function takes the remainder of the program as input and returns a program as output, pulling elements from the front of the input program and pushing elements to the back of the output program.

Terms

Only terms (operators and operands) are significant to functions; separators are discarded from input, and are inserted between output terms in a "normalized" form (for consistent formatting and proper operator separation). Therefore, only input and output terms are relevant in describing a function.

Types

There are three fundamental types of functions:

  • Identity: A function that pushes all input terms onto the output program.
  • Constant: A function that pushes a term defined by the function, followed by all input terms, onto the output program.
  • Operation: A function that is named by an operator and defines a computation. An operation processes input operands as data for the computation, and pushes any terms generated by the computation onto the output program, until one of two things happens:
    • If the computation is completed, the rest of the input terms are pushed onto the output program.
    • If the computation cannot be completed (due to insufficient operands), the operator that names the operation is pushed onto the output program, followed by all remaining input terms.

Evaluation

Empty Program

The empty program evaluates to the identity function.

Single-Element Programs

Programs that contain only a single element evaluate to functions as follows:

  • Separator: Evaluates to the identity function.
  • Operand: Evaluates to a constant function that pushes the operand, followed by all input terms, onto the output program.
  • Operator: Evaluates to the operation defined for the operator in the environment. If none, evaluates to a constant function that pushes the operator, followed by all input terms, onto the output program.

Multiple-Element Programs

Programs that contain multiple elements can be considered a concatenation of sub-programs that each contain one of the elements. Om is a concatenative language: the concatenated program evaluates to the composition of the functions that each sub-program evaluates to.

For example, program "A B" is the concatenation of programs "A", " ", and "B". The separator evaluates to the identity operation and can be disregarded. The programs "A" and "B" evaluate to functions which will be denoted as A and B, respectively. The input and output are handled by the composed function as follows:

  • Function B receives the input, and its output becomes the input for function A.
  • Function A receives the input, and its output becomes that of the composed function.

Any programs may be concatenated together; however, note that concatenating programs "A" and "B" without an intervening separator would result in a program containing a single operator "AB", which is unrelated to operators "A" or "B".

Operations

All operation implementations provided are documented in the Operations module.