Monad-like structures in Mathematica

General

My (biased) view on monads is that they are loudly advertised in Haskell and F#, but I kind of do not see what is the big deal. (Granted, similar things are said about OOP Design Patterns, but I like them and use them a lot.)

Monad programming is more important for functional programming languages like Haskell because of their strong type function definition. Not so much in LISP-like languages.

Monad programming style is not so hard to apply/use in LISP or Mathematica. That can be done in at least several ways:

  • one way using code generation is detailed in my answers in the discussion "How and why to use monadic programming in Mathematica?" and in this blog post;

  • another (more direct) way is described below.

Monadic programming example (in Mathematica)

This functional parsers implementation in Mathematica, FunctionalParsers.m, introduced and demonstrated in these blog posts, is an application of the "monadic programming" style. Recent developments in Mathematica make the use of that style much easier.

The monad for the functional parsers in FunctionalParsers.m is defined for the functions

P: {{_String...}, _ParseTree } -> { {{_String...}, _ParseTree } ... }

This definition allows the chaining of parsers that are of basic, combinator, or transforming types. (This kind of chaining is discussed here.)

For more detailed definitions and explanations see "Functional parsers for an integration requests language grammar".

MSE links to applications

The reason I am listing these applications is because in order to implement functional parsers packages in Mathematica, R, and Lua I followed the monad style in the Haskell based article "Functional parsers" by Fokker. Hence successful applications would demonstrate the monads usefulness.

  1. This answer for the question "How to parse a clojure expression?".

  2. This answer for the question "Programming of a natural language interface".

  3. This answer for the question "Writing functions with “Method” options".

  4. On the code re-factoring and design side, this answer for the question "Functions with changeable global variables".


Your question is very broad. A full answer would require a lengthy tutorial on meta-programming in Mathematica. I'm not going to come anywhere close to doing that, but I will give you a hint to help you get started.

There are essentially two ways to introduce emulations of concepts from another programming language (OPL) into Mathematica (WL).

  1. Determine what built-in functions in WL provide identical or similar functionality or can be combined to provide such functionality as is found in OPL. Then use the WL equivalents to implement what ever application you have in mind. With this approach you have work with normal WL syntax and your finished application will likely look quite different than it would look if it were implemented in OPL.

  2. Introduce new syntax into WL that emulates the OPL syntax. This can be done, but it requires, in addition to carrying out what was discussed under 1), writing a preprocessor to convert OPL syntax into WL syntax and (often) a postprocessor to convert WL syntax into OPL syntax.

You reject limiting yourself to the first approach, which can be difficult enough in itself and are asking how to do the second, which piles Pelion upon Ossa, but if you are up to it, I salute you.

WL has some hook symbols that allow you install syntax conversion functions into the top-level processing loop. Basically, you define a function to do the conversion and set the appropriate hook to be that function. An input hook will be applied to any top-level user input. An output hook to any top-level evaluator output.

The hooks you should look at are $Pre, $PreRead, $PrePrint, and $Post. The Documentation Center has examples on the use of these hooks and you can find more examples on this site.


Thanks to the suggestion of m_goldberg, I have found the following solution. We use the $Post hook as follows:

notcom := (# =!= comment) &;
commentprocessor = Function[expression,
FixedPoint[
# /. {f_?notcom[z___, comment[x_, w___], y___] :> comment[f[z, x, y], w], 
comment[comment[xx_, w___], z___] :> comment[xx, w, z]} &,
expression]
]
$Post = commentprocessor

then,

N[Sin[comment[1, "One"] - E^comment[0, "Zero"]]]

returns, as expected

comment[0., "Zero", "One"]

and

Sin[comment[Pi, "abc"]] + 1

comment[1, "abc"].