Message Boards Message Boards

Metaprogramming in the Wolfram Language

For some time now I have been interested in the idea of metaprogramming in the Wolfram Language. That WL lends itself to metaprogramming appeared so clear cut to me that I was surprised to find that the subject hasn't really come up in the community.

Not being a computer scientist (when I studied computer science at university, it was with the benefit of punched cards), I began to wonder if I had misapprehended something fundamental about WL. Happily, the talented Leonid Shifrin has taken a keen interest in the subject and written extensively about it, including this excellent post on Stack Exchange, in which he lays out the fundamental concepts. His view is that:

Mathematica is very well suited for meta-programming, and one can write much more powerful programs in Mathematica by utilizing it.

I will pick out a couple of the highlights here, but I would recommend a thorough reading of Leonid's post in its entirety.

Introspection

Writes Leonid:

Mathematica is IMO very strong here. There are a couple of reasons for this: Homoiconic language (programs written in own data structures - Mathematica expressions. This is code-as-data paradigm, like Lisp which uses lists for this) One can access global definitions for symbols stored in OwnValues, DownValues, SubValues, UpVaulues, etc, and various other global properties, programmatically. Rule-based destructuring techniques (using Cases etc) seriously simplify many introspection-related operations

An excellent example of WL's capabilities is given in a related post on automatically generating a dependency graph of an arbitrary Mathematica function.

enter image description here

Run-time Code Generation

Leonid goes on to write about WL's capabilities in this type of metaprogramming, including making JIT-compiled functions. He gives the following example:

ClearAll[selectJIT];
selectJIT[pred_, listType_] :=
  selectJIT[pred, Verbatim[listType]] = 
    Block[{lst},
     With[{decl = {Prepend[listType, lst]}},
      Compile @@ 
       Hold[decl, Select[lst, pred], CompilationTarget -> "C", 
          RuntimeOptions -> "Speed"]]];

which is tested in the following example:

test = RandomInteger[{-25, 25}, {10^6, 2}];
selectJIT[#[[2]] > 0 &, {_Integer, 2}][test] // Short // AbsoluteTiming 
selectJIT[#[[2]] > 0 &, {_Integer, 2}][test] // Short // AbsoluteTiming

(*

 ==> {0.4707032,{{-6,9},{-5,23},{-4,4},{13,3},{-5,7},{19,22},<<489909>>,{11,25},{-6,5},
          {-24,1},{-25,18},{9,19},{13,24}}}

 ==> {0.1250000,{{-6,9},{-5,23},{-4,4},{13,3},{-5,7},{19,22},<<489909>>,{11,25},{-6,5},
          {-24,1},{-25,18},{9,19},{13,24}}}
*)

The second time it was several times faster because the compiled function was memoized.

Macros

This is what is foremost in my mind when thinking about metaprogramming. Specifically, a macro in the context of WL means a construct which

  • Manipulates pieces of Mathematica code as data, possibly preventing them from (premature) evaluation
  • Expands code at run-time (not "read-time" or "compile-time", which are not so well defined in Mathematica)

Leonid offers several examples of WL metaprogramming macros in his own and other Stack Exchange posts that the reader is encouraged to explore. He also points out some of the deficiencies of WL in this context, which include hard to control evaluation and the lack of a clearly delineated compilation stage.

Wolfram Alpha for WL

Some limited metaprogramming capabilities for code generation are built into Wolfram Alpha. So, for instance, the Wolfram Alpha query Integrate Log(x) will produce not only the result,

enter image description here

but also the appropriate WL code for evaluating the indefinite integral, i.e.

Integrate[Log[x], x]

But suppose we wanted some help to generate code to do something a little more complicated - say, for example, to solve one of the problems in Stephen Wolfram's Elementary Introduction to the Wolfram Language.

enter image description here

So how would one proceed to develop a more useful WL macro generator?

Before offering some suggestions and ideas, I'll press pause here in the hope of opening up the discussion - this is quite a long post already and I would like to gauge the level of interest in a continuation (if any!).

POSTED BY: Jonathan Kinlay

So how would one proceed to develop a more useful WL macro generator?

There are least several general approaches for this; selecting which one to use depends on the scope of what we want to accomplish.

Given the Wolfram Alpha example you posted we can take a conversational engine approach -- see for example this Mathematica Stack Exchange post : "Programming of a natural language interface". The package "FunctionalParsers.m" is an example of meta-programming -- it generates the Mathematica code for parsers from Extended Backus Naur Form (EBNF) grammar specifications.

enter image description here

POSTED BY: Anton Antonov
Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments
Remove
or Discard

Group Abstract Group Abstract