🏠 🌘

my blog


kacper topolnicki
kacpertopol@gmail.com

monads and “do” notation in the Wolfram Language, part 2

2021-02-04

introduction of monadic types …

This is the second post in of a series on the “do” notation in the Wolfram Language. In the first post a categorical interpretation of the Wolfram Language was introduced. Now it is time for monads.

A user can implement a monad m in the WL by supplying three definitions. The first definition:

    pattern[m] = (*pattern m a*)

provides a pattern that matches a WL expression if it is an m monad for any type argument a. The second definition implements the monadic return function:

    return[m][x_] := (*expression matching pattern[m]*)

if the type of x is a then this expression should be a m monad for type argument a. In particular the resulting WL expression should match pattern[m]. The final definition is an implementation of the monadic bind operator for m:

    bind[m][ma_ , aTOmb_] := (*implementation of bind*)

where ma is an m monad for type argument a and aTOmb is a function taking an element of type a and returning an m monad for type argument b. The user does not have to supply additional pattern constraints in bind, however it is up to the user to make sure that these definitions result in an object that satisfies the monad laws.

Having these three definitions for monad m, the implementation of the “do" notation in the WL is straightforward and consists of two parts. The first is a recursive definition that reduces the do[m] expression by applying the user defined bind[m] operator:

    do[m_][x___ , y_ , r:Except[_LeftArrow]]:= 
       If[MatchQ[y , LeftArrow[_ , _]] , 
          do[m][x , 
             chk[m][
             bnd[m][snd[y] , 
                Function[Evaluate[fst[y]] , r]]]
             ],
          do[m][x , 
             chk[m][bnd[m][y , 
                Function[Unique["nonExistantVariable"] , r]]]
          ]
       ];

Here bnd[m] will be replaced by the appropriate user supplied bind[m] function when the first argument matches pattern[m] and the second argument is a function, fst, snd are helper functions that take the left and right expression from a LeftArrow statement, and finally chk[m] is a function that checks the result of bind[m] against the user defined pattern[m]. Once do[m] is reduced to a contain a single expression the final expression is checked and returned:

    do[m_][mx_]:=chk[m][mx];

These definitions together with the supplementary functions are provided for the readers convenience here. The repository contains a short WL package wlmonad.wl and a number of examples. Next time we will look at the Hanoi Tower example.