Mascarpone

From Esolang
Jump to navigation Jump to search

Mascarpone is a stack-based, self-redefining programming language designed by Chris Pressey in 2007 as a successor to Emmental. In Mascarpone, meta-circular interpreters are first-class values; the interpreter currently being used to interpret the program may be pushed onto the stack ("reified") and manipulated, and an interpreter on the stack may be popped and used as the interpreter for the following part of the program ("deified").

While the author has never really been sure of the extent to which Mascarpone "counts" as an esoteric programming language, from a typical programmer's point of view, it is not obvious how to program in it, and programs in it are borderline-unreadable strings of symbols.

Execution

Meta-circular interpreter

In Mascarpone, an interpreter is a map that takes symbols to operations, and an operation is a sequence of symbols that is given meaning by some interpreter.

There is a special interpreter in Mascarpone called "null". It is an error to try to interpret anything with this interpreter.

Every interpreter (except for null) is linked to a "parent" interpreter (which may be null.) No interpreter can be its own ancestor; the parent-child relationships between interpreters form a directed, acyclic graph (or DAG.)

There is, at any given time in a Mascarpone, a current interpreter: this is the interpreter that is in force, that is being used to interpret symbols. The parent interpreter of the current interpreter is generally the interpreter that was used to execute the current operation (that is, the operation currently being interpreted; it consists of a string of symbols is interpreted by the current interpreter.)

The current interpreter when any top-level Mascarpone program begins is the initial Mascarpone interpreter.

Stacks

Mascarpone has a stack, that can contain symbols, operators, and interpreters. Strings are popped from the stack beginning with popping a "[" symbol and ending with popping a "]" symbol. Strings can be nested.

By using a parent-child relationship between interpreters, Mascarpone can emulate second stack. By getting the current interpreter, modifying it, setting it's parent to be the current interpreter, and setting it as the current interpreter (in Mascarpone: v...v}^), we "push" something onto it; by getting the current interpreter, getting its parent, and setting that as the current interpreter (v{^), we "pop".

Actually, even if there was no explicit parent-child relationship between interpreters, we'd still be able to store a stack of interpreters, because each operation in an interpreter has its own interpreter that gives meaning to the symbols in that operation, and that interpreter can contain operations that can contain interpreters, etc., etc., ad infinitum.

Initial Mascarpone interpreter

Command Name Description
v Reify pushes the current interpreter onto the stack.
^ Deify pops an interpreter from the stack and installs it as the current interpreter.
> Extract pops a symbol from the stack, then pops an interpreter. It pushes onto the stack the operation associated with that symbol in that interpreter.
< Install pops a symbol from the stack, then an operation, then an interpreter. It pushes onto the stack a new interpreter which is the same as the given interpreter, except that in it, the given symbol is associated with the given operation.
{ Get parent pops an interpreter from the stack and pushes it's parent interpreter onto the stack.
} Set parent pops an interpreter i from the stack, then pops an interpreter j. It pushes a new interpreter which is the same as i, except that it's parent interpreter is j.
* Create pops an interpreter from the stack, then a string. It creates a new operation defined by how that interpreter would interpret that string of symbols, and pushes that operation onto the stack.
@ Expand pops an operation from the stack and pushes a program string, then pushes an interpreter, such that the semantics of running the program string with the interpreter is identical to the semantics of executing the operation. (Note that the program need not be the one that the operation was defined with, only equivalent to it, under the given interpreter; this allows one to sensibly expand "intrinsic" operations like those in the initial Mascarpone interpreter.)
! Perform pops an operation from the stack and executes it.
0 Null pushes the null interpreter onto the stack.
1 Uniform pops an operation from the stack and pushes back an interpreter where all symbols are associated with that operation.
[ Deepquote pushes "[" and enters deepquote mode, which pushes symbols to the stack until "]"(can be nested).
' Quotesym pushes to the stack the symbol after it.
. Output pops a symbol off the stack and sends it to the standard output.
, Input waits for a symbol to arrive on standard input, and pushes it onto the stack.
: Duplicate duplicates the top element of the stack.
$ Pop pops the top element of the stack and discards it.
/ Swap swaps to the top two elements of the stack.

Examples

Hello world

[!dlrow olleH]$............$

Truth machine

'[,']['0.]v*1['1.[1]v{*!]v*'1<*!

It works using uniform interpreter with operation that prints 0 and installing operation that prints 1 and executes itself.

Checks if length of the string is even

[1][(enter any string)]
[[[1]]v*1[ [0] ]v*'1<*!]v*1*!
$.$

External resources