PolyStack

From Esolang
Jump to navigation Jump to search

PolyStack is an esoteric programming language and Domain-Specific Language designed to serve as the Type System for other programming languages, particularly stack-based ones. It aims to be a powerful type system for stack- and deque- based languages, itself being deque-based. It aims to be so powerful, in fact, that it is hoped to be Turing-complete in its final form.

Syntax

PolyStack is similar to any other concatenative programming language, having an RPN format for its instructions. In order to thoroughly integrate with W, the language for which it was primarily defined, it does some fiddling with the logical syntax; however, an alternative standalone syntax is also available.

As a stack-based language, the commands are a series of instructions separated by spaces. In the default version, quotes delimit a quoted string, which can be pushed onto a secondary stack, whereas in the alternative version, there are no quotes. All other instructions are commands; either types (which just push their type onto the stack) or manipulation commands (which actually do stuff).

The primary stack can hold three things: Scalar Types, Type Classes, and Compound Types. Scalar Types are the types of scalar data; for example, Int or Float or Char. Type classes represent sets of types, such as Num. Compound types are full type expressions; the type of a function in Haskell. A Compound Type might be (Char Int -- Float) or (Ord x) => (x..y -- y..x). Unlike Haskell types, which return exactly one value (which may be a collection, but is one value nonetheless) from a single list of inputs, PolyStack types accept two lists of inputs and two lists of outputs, representing the values POPed and the values PUSHed. This means that PolyStack types can return multiple values, though this can be constrained in implementations.

An example of a PolyStack program is:

"x" pmt Ord <-> constrain <| ?<

Which always returns True through a convoluted process.

Type Expressions

Type Expressions in PolyStack are based off of Forth's type expressions. They are of the following form:

(Tc1 x, Tc2 y, Tc3 z) => (a b..c d -- e f..g h)

This tells the computer the following:

  • The polymorphic variables x, y, and z must belong to the typeclass Tc1, Tc2, and Tc3, respectively
  • The arguments of types a and b are POPed from the front of the deque (first b, then a)
  • The arguments of types c and d are POPed from the back of the deque (first d, then c)
  • The results of types e and f are PUSHed onto the front of the deque
  • The results of types g and h are PUSHed onto the back of the deque

Argument types can be either polymorphic (lowercase) or static (capitalized). When padded in square brackets, they form a list; in curly brackets forms a set, and a comma-separated list in parenthesis forms a tuple. A type of the form {a:b} is a dict mapping elements of type a to type b, and if the curlies are replaced with square brackets it forms an ordered dict of the same type. Finally, an argument can be another type expression padded in parenthesis.

Builtin Types, Type Classes, etc.

A list of the Builtin Type Classes is:

Name Recommended Usage Constraints
Num For numbers that can be manipulated: added, subtracted, etc. Ord
Ord A value which can be compared (is this greater than/less than/other) another value? Eq
Eq Are these two values equal? N/A

The builtin types, and the classes they belong to, are:

Name Meaning Type Classes
Int A number positive or negative; just must not have a fractional part Num
Float A real number; any number, really. Num
Complex A number with both a real and an imaginary part (both floats) Num
Char A single Unicode character (any plane) Ord
String [Char] Ord
None A null value; no data. N/A
Some A non-null value with no data N/A

Commands

This section covers the commands available to the user in PolyStack.

Deque Manipulation
Command Laconic Meaning Type
DUP : Pop a value, push it twice (a -- a a)
DROP $ Pop a value, discard it (a -- )
SWAP \ Pop two values, push them s.t. they are reversed in order (a b -- b a)
ROLL |> Pop a value, move it to the back of the deque (a -- ..a)
REVROLL <| Eject a value, move it to the front of the deque (..a -- a)
PAD <-> Pop a value, push it at both the front and back of the deque (a -- a..a)
BACKPAD <~> Eject a value, push it at both the front and back of the deque (..a -- a..a)
Scalar Types
Command Laconic Meaning Type
(Typename) N/A Push the type of that name ( -- a)
POLY ~ Pop a string from the secondary stack, push it as a polymorphic variable on the main stack ( -- a)
Compound Types
Command Laconic Meaning Type
LIST [] Pop a type, push its list type (a -- [a])
TUPLEn (,,,) (with n commas) Pop n types, push them in a tuple (*a -- (*a))
Type Classes
Command Laconic Meaning Type
(Typeclassname) N/A Push the typeclass of that name ( -- a)
?< N/A Pop a type, pop a typeclass, push Some if that type is in that typeclass, else push None ( -- a)