Printable Version of this PageHome PageRecent ChangesSearchSign In

L Highlights

L is a language & system influenced by Smalltalk, Scheme, and E.

Late binding

Variables references (words) are just messages sent to the current lexical scope. The lexical scope may change dynamically, like when defining a new word or importing a dictionary of them.

Simple syntax and semantics

There are only three types of expressions in the abstract syntax: Literal, CurrentScope, and Apply. Every value is a function and every action is a function application (call).

Object oriented

Most functions in L (such as the current lexical scope) are objects, that is, they are functions from selectors to values/functions. Object orientation is just a convention that says to make the operator/selector the first argument instead of the receiver.

Currying

If too many arguments are supplied to a function, the extra arguments are supplied to the result. This allows full object-oriented messages to be sent to an object which really just accepts the first argument, the selector, and returns a function that then takes the remaining arguments. If too few arguments are supplied to a function, a function is returned that upon receiving the remaining arguments will invoke the orginal function with all the arguments.

Dynamic types

Types are first-class values. They represent (possibly infinite) sets, and can be any object that responds to 'includes. If a parameter has an associated type, the supplied argument is tested for inclusion before being bound to the parameter. Where feasible, the compiler checks types statically and optimizes.

Meta information

Types and other meta information are useful at runtime. For instance, you may ask an object for all the selectors it understands. You don't ask (invoke) the object or function directly, rather you get its meta view and send messages to it.

Threaded mutable state

A thread environment is implicitly passed on every function application and return (a la monads or dynamic scope). Pure functions perform "side-effects" by returning a new thread with bindings in it that shadow old ones. The keys can be private (for mutable private state) or public (for shared thread-global variables).

Parallel computation

All sub-expressions of an expression are computed independently. Each forks a new thread environment and lexical scope. When they all return, the resulting threads and scopes are merged together (a la transaction commit) and supplied to the outer expression. The compiler translates abstract syntax trees to graphs to represent this parallel flow of execution.

L all the way down

Machine instructions are represented as functions, and all values in the system can be viewed in its raw tuple (memory structure) form. The garbage collector, compiler, etc. are all written in L, and editable by users who have references to the right tools (functions).

Capability-based security

Lexical scope and unforgeable immutable references provide capability-based security. You only have access to what you can reference in your current lexical scope. Low-level functions that can access memory, etc. are only available within certain privileged scopes.

Graphical "shell" interface

Every user has his own environment (lexical scope) and open transaction (thread environment) in which he operates. Commands and results are displayed in graph form yielding a function graph syntax, which can be saved as a function for future use. This interface is an alternative to spreadsheets as well as command-lines.