Unlambda

Last updated
Unlambda
Paradigm Nearly pure functional
Designed by David Madore
Developer David Madore
First appeared28 June 1999;23 years ago (1999-06-28)
Stable release
2.0.0 / 20 December 1999;23 years ago (1999-12-20)
Typing discipline Untyped
Implementation language Scheme, C, Java
License GPL 2.0 or later
Website www.madore.org/~david/programs/unlambda

Unlambda is a minimal, "nearly pure" [1] functional programming language invented by David Madore. It is based on combinatory logic, an expression system without the lambda operator or free variables. It relies mainly on two built-in functions (s and k) and an apply operator (written `, the backquote character). These alone make it Turing-complete, but there are also some input/output (I/O) functions to enable interacting with the user, some shortcut functions, and a lazy evaluation function. Variables are unsupported.

Contents

Unlambda is free and open-source software distributed under a GNU General Public License (GPL) 2.0 or later.[ clarification needed ]

Basic principles

As an esoteric programming language, Unlambda is meant as a demonstration of very pure functional programming rather than for practical use. Its main feature is the lack of conventional operators and data typesthe only kind of data in the program are one-parameter functions. Data can nevertheless be simulated with appropriate functions as in the lambda calculus. Multi-parameter functions can be represented via the method of currying.

Unlambda is based on the principle of abstraction elimination, or the elimination of all saved variables, including functions. As a purely functional language, Unlambda's functions are first-class objects, and are the only such objects.

Here is an implementation of a hello world program in Unlambda: [1]

`r```````````.H.e.l.l.o. .w.o.r.l.di

Original built-in functions

The notation .x denotes a function which takes one argument and returns it unchanged, printing the single character x as a side effect when it is invoked. i represents the version of the identity function that has no such side effect; it is used here as a dummy argument. The program `.di applies the d-printing function to a dummy argument of i, returning i and printing the letter d as a side effect. Similarly, ``.l.di first applies .l to .d, printing the letter l and returning .d; this result of .d is then applied to i as in the previous example. The function r is syntactic sugar for the function that prints a newline character.

Other important features provided by Unlambda include the k and s functions. k manufactures constant functions: the result of `kx is a function which, when invoked, returns x. Thus the value of ``kxy is x for any x and y.

s is a generalized evaluation operator. ```sxyz evaluates to ``xz`yz for any x, y, and z. It is a remarkable fact that s and k are sufficient to perform any calculation, as described in SKI combinator calculus. As a brief example, the identity function i can be implemented as ``skk, since ```skkx yields x for all x.

Unlambda's one flow control construct is call with current continuation, denoted c. When an expression of the form `cx is evaluated, a special continuation object is constructed, representing the state of the interpreter at that moment. Then x is evaluated, and then the result is given the continuation object as an argument. If the continuation is never applied to an argument, the value of the `cx expression is the same as the value of x. But if the continuation object is applied to a value y, execution of x is immediately aborted, and the value of the entire `cx expression is y.

Unlambda's execution semantics are normally eager evaluation, but a lazy evaluation option exists, indicated by the use of the d operator. Usually, to evaluate an expression of the form `xy, unlambda first evaluates x, then y, and then applies x to y. However, if x evaluates to the special value d, then y is not evaluated; instead, the value of the expression `dy is a special "delayed computation" object, which, when applied to an argument z, evaluates y, and then applies its value to z. In the absence of side effects, this is exactly the same as `iy. The difference is that `iy executes any side effects in y immediately, whereas `dy defers the side effects until the result is applied to another argument.

Unlambda's next built-in operator is v, which ignores its argument and returns v. This feature is not strictly necessary, since v could be implemented as ``s`k``s``s`kskk`k``s``s`kskk, but it is supplied as a convenience. (This expression above is simply `Yk, where Y denotes a fixed point combinator.)

Version 2 built-in functions

More built-ins were introduced in Unlambda version 2. Input is facilitated by operators @ and ?u. When @ is applied to a function x, a character is read from input, and stored as the "current character"; then x is applied to i. However, if no more characters were available on input, the current character is left undefined, and x is applied to v instead. When a function ?u is applied to a function x, the result is the evaluation of `xi if the current character is u, otherwise `xv is evaluated.

There is also a "reprint" operator |. When `|x is evaluated, the function x is applied to .u if u is the current character, or to v if there is no current character.

Finally, there is an exit operator e. When e is applied to x, the execution of the program is terminated, and x is taken as the result of the program (most of the currently existing interpreters ignore the result anyway).

See also

Related Research Articles

In computer science, functional programming is a programming paradigm where programs are constructed by applying and composing functions. It is a declarative programming paradigm in which function definitions are trees of expressions that map values to other values, rather than a sequence of imperative statements which update the running state of the program.

Lambda calculus is a formal system in mathematical logic for expressing computation based on function abstraction and application using variable binding and substitution. It is a universal model of computation that can be used to simulate any Turing machine. It was introduced by the mathematician Alonzo Church in the 1930s as part of his research into the foundations of mathematics.

<span class="mw-page-title-main">Scheme (programming language)</span> Dialect of Lisp

Scheme is a dialect of the Lisp family of programming languages. Scheme was created during the 1970s at the MIT AI Lab and released by its developers, Guy L. Steele and Gerald Jay Sussman, via a series of memos now known as the Lambda Papers. It was the first dialect of Lisp to choose lexical scope and the first to require implementations to perform tail-call optimization, giving stronger support for functional programming and associated techniques such as recursive algorithms. It was also one of the first programming languages to support first-class continuations. It had a significant influence on the effort that led to the development of Common Lisp.

In logic, mathematics, and computer science, arity is the number of arguments or operands taken by a function, operation or relation. In mathematics, arity may also be called rank, but this word can have many other meanings. In logic and philosophy, arity may also be called adicity and degree. In linguistics, it is usually named valency.

In programming languages, a closure, also lexical closure or function closure, is a technique for implementing lexically scoped name binding in a language with first-class functions. Operationally, a closure is a record storing a function together with an environment. The environment is a mapping associating each free variable of the function with the value or reference to which the name was bound when the closure was created. Unlike a plain function, a closure allows the function to access those captured variables through the closure's copies of their values or references, even when the function is invoked outside their scope.

In mathematics, and in other disciplines involving formal languages, including mathematical logic and computer science, a free variable is a notation (symbol) that specifies places in an expression where substitution may take place and is not a parameter of this or any container expression. Some older books use the terms real variable and apparent variable for free variable and bound variable, respectively. The idea is related to a placeholder, or a wildcard character that stands for an unspecified symbol.

Combinatory logic is a notation to eliminate the need for quantified variables in mathematical logic. It was introduced by Moses Schönfinkel and Haskell Curry, and has more recently been used in computer science as a theoretical model of computation and also as a basis for the design of functional programming languages. It is based on combinators, which were introduced by Schönfinkel in 1920 with the idea of providing an analogous way to build up functions—and to remove any mention of variables—particularly in predicate logic. A combinator is a higher-order function that uses only function application and earlier defined combinators to define a result from its arguments.

In mathematics and computer science in general, a fixed point of a function is a value that is mapped to itself by the function.

In mathematics and computer science, a higher-order function (HOF) is a function that does at least one of the following:

In computer programming, a parameter or a formal argument is a special kind of variable used in a subroutine to refer to one of the pieces of data provided as input to the subroutine. These pieces of data are the values of the arguments with which the subroutine is going to be called/invoked. An ordered list of parameters is usually included in the definition of a subroutine, so that, each time the subroutine is called, its arguments for that call are evaluated, and the resulting values can be assigned to the corresponding parameters.

In computer science, a continuation is an abstract representation of the control state of a computer program. A continuation implements (reifies) the program control state, i.e. the continuation is a data structure that represents the computational process at a given point in the process's execution; the created data structure can be accessed by the programming language, instead of being hidden in the runtime environment. Continuations are useful for encoding other control mechanisms in programming languages such as exceptions, generators, coroutines, and so on.

In functional programming, a monad is a structure that combines program fragments (functions) and wraps their return values in a type with additional computation. In addition to defining a wrapping monadic type, monads define two operators: one to wrap a value in the monad type, and another to compose together functions that output values of the monad type. General-purpose languages use monads to reduce boilerplate code needed for common operations. Functional languages use monads to turn complicated sequences of functions into succinct pipelines that abstract away control flow, and side-effects.

In mathematics, an expression or mathematical expression is a finite combination of symbols that is well-formed according to rules that depend on the context. Mathematical symbols can designate numbers (constants), variables, operations, functions, brackets, punctuation, and grouping to help determine order of operations and other aspects of logical syntax.

In some programming languages, eval, short for the English evaluate, is a function which evaluates a string as though it were an expression in the language, and returns a result; in others, it executes multiple lines of code as though they had been included instead of the line including the eval. The input to eval is not necessarily a string; it may be structured representation of code, such as an abstract syntax tree, or of special type such as code. The analog for a statement is exec, which executes a string as if it were a statement; in some languages, such as Python, both are present, while in other languages only one of either eval or exec is.

In functional programming, continuation-passing style (CPS) is a style of programming in which control is passed explicitly in the form of a continuation. This is contrasted with direct style, which is the usual style of programming. Gerald Jay Sussman and Guy L. Steele, Jr. coined the phrase in AI Memo 349 (1975), which sets out the first version of the Scheme programming language. John C. Reynolds gives a detailed account of the numerous discoveries of continuations.

In the Scheme computer programming language, the procedure call-with-current-continuation, abbreviated call/cc, is used as a control flow operator. It has been adopted by several other programming languages.

The SKI combinator calculus is a combinatory logic system and a computational system. It can be thought of as a computer programming language, though it is not convenient for writing software. Instead, it is important in the mathematical theory of algorithms because it is an extremely simple Turing complete language. It can be likened to a reduced version of the untyped lambda calculus. It was introduced by Moses Schönfinkel and Haskell Curry.

In a programming language, an evaluation strategy is a set of rules for evaluating expressions. The term is often used to refer to the more specific notion of a parameter-passing strategy that defines the kind of value that is passed to the function for each parameter and whether to evaluate the parameters of a function call, and if so in what order. The notion of reduction strategy is distinct, although some authors conflate the two terms and the definition of each term is not widely agreed upon.

In computer programming, an anonymous function is a function definition that is not bound to an identifier. Anonymous functions are often arguments being passed to higher-order functions or used for constructing the result of a higher-order function that needs to return a function. If the function is only used once, or a limited number of times, an anonymous function may be syntactically lighter than using a named function. Anonymous functions are ubiquitous in functional programming languages and other languages with first-class functions, where they fulfil the same role for the function type as literals do for other data types.

In mathematics and computer science, apply is a function that applies a function to arguments. It is central to programming languages derived from lambda calculus, such as LISP and Scheme, and also in functional languages. It has a role in the study of the denotational semantics of computer programs, because it is a continuous function on complete partial orders. Apply is also a continuous function in homotopy theory, and, indeed underpins the entire theory: it allows a homotopy deformation to be viewed as a continuous path in the space of functions. Likewise, valid mutations (refactorings) of computer programs can be seen as those that are "continuous" in the Scott topology.

References

  1. 1 2 Chu-Carroll, Mark C. (2006-08-11). "Friday Pathological Programming: Unlambda, or Programming Without Variables". Good Math, Bad Math (blog). ScienceBlogs.