Metalua is a metaprogramming extension to Lua 5.1, i.e. a compiler which allows to extend the language's syntax and semantics from within programs

The subtitle for the homepage is: "Lisp extensibility, Lua syntax"

The two "samples" are rather impressive:

Typechecking introduces optional runtime type checking into Lua. It features syntax extension (addition of a typing operator), existing syntax modification (functions get their parameters and returned values checked), and non-local code modification (return statements in functions are chased down to get additional typechecking code).

Pattern matching demonstrates how to add pattern matching, a distinctive feature of languages from the ML family, into Lua. These complex testing control statements are compiled into a (possibly long) list of if statements and local variables bindings. They are supported by a syntax extension which shows how to save a lot of work by reusing Lua's expression syntax with a very different semantics.

Note for ML programmers: I feared that pattern matching without type inference would be hard to use; it's actually quite pleasant, and I hadn't many issues with the lack of static typing.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

Pattern Matching

I may be wrong, but I think pattern matching predates ML. I generally associate the technique with logic languages and unification. Languages like Oz and Erlang, both descendents of Prolog, have pattern matching without static typing.

As an example, I've been tinkering with EOPL. And since there's a call for more code on Ltu, here's a snippet of Alice ML code for section 1.3:

datatype expression = Id of symbol
                    | Lambda of symbol * expression
                    | Apply of expression * expression

fun occurs_free (var, Id sym)             = (var = sym)
  | occurs_free (var, Lambda(id, body))   = (id <> var) andalso occurs_free(var, body)
  | occurs_free (var, Apply(rator, rand)) = occurs_free(var, rator) orelse occurs_free(var, rand)

val f = Apply(Lambda("x", Id "x"), Id "y")
val a = occurs_free("x", f)
val b = occurs_free("y", f)

And here's a similar snippet for Oz:

fun {OccursFree Var Exp}
   case Exp
   of [id Sym]           then (Var == Sym)
   [] [lambda Id Body]   then {Not (Id == Var)} andthen {OccursFree Var Body}
   [] [apply Rator Rand] then {OccursFree Var Rator} orelse {OccursFree Var Rand}

F = [apply [lambda x [id x]] [id y]]
A = {OccursFree x F}
B = {OccursFree y F}

The EOPL authors also introduce a define-datatype syntax for Scheme in chapter 2 that accomplishes much the same.

Arguably patternmatching is

Arguably patternmatching is even older, orginating in COMIT in the early sixthis.

Pattern matching

There appears to be some ambiguity about pattern matching here. Mathematicians for centuries have used case analysis to define functions:

signum(x) =  
        -1      (x<0)
         0      (x=0)
         1      (x>0)

which is semantiaclly equivalent to a lisp COND or a chain of nested IFs.

Structure-matching showed up in many early AI languages but finds, as Chris points out, its apotheosis in unification and

Full-fledged string pattern-matching, equivalent to parsing, showed up in Comit and SNOBOL but I don't know of any (until Cduce) that used it for either pattern-based invocation or argument destructuring.

One could go further: consider "pattern unification" in which you equate two grammar-like patterns, a la Snobol, complete with logical variables for some of the terminals, and the result is another such pattern, also perhaps with variables, which expresses the language which is the intersection of the two.


metalua 0.3

version 0.3 of metalua just shipped, with new doc, new site, new samples.