Introduction
Introduction
I have been learning Haskell recently, and I decided to see if I could implement monads in the Wolfram language. To test this, I’ve also implemented a version of Haskell’s “do” notation, and the “state” monad.
Issues
Issues
One issue I ran into is that the Wolfram Language does this:
Function
In[]:=
foo[f_]:=x|->f[x]
In[]:=
Nest[foo,b,3]
Out[]=
Function[x$,Function[x$,Function[x$,b[x$]][x$]][x$]]
Which ended up causing problems for my function when people used the “” syntax for defining functions in their monads. One can get around this by defining foo equivalently as
In[]:=
foo[f_]:=f[#]&
In[]:=
Nest[foo,b,3]
Out[]=
((b[#1]&)[#1]&)[#1]&
(the answer I wanted) but I want the user of the monads to not have to worry about what specific syntax they use for defining functions, and that they might get the wrong answer if they use the “wrong” syntax. So Kurt Gimbel helped me with that part, and did almost all of the design of the “uniquizeVars” function which makes sure that nested functions always have unique variables when they are supposed to be unique. If one avoids using the “” or Function syntax with named variables, one can just do away with that function, and the definition for the monads would look a bit more elegant. But I wanted that feature so it’s here.
Below I define the code for the “do” notation and the “state” monad, and then set up and run some composed stateful computations involving pushing and popping, with the defined “do” notation.
Below I define the code for the “do” notation and the “state” monad, and then set up and run some composed stateful computations involving pushing and popping, with the defined “do” notation.
Do Notation Code
Do Notation Code
In[]:=
then[x_,y_]:=bind[x,y&]
In[]:=
myValueQ[expr_]:=ValueQ[expr,Method->"SymbolDefinitionsPresent"]||Context[expr]==="System`"
In[]:=
uniqueizeVars[expr_]:=Module[{},expr/.(Symbol[#]:>With[{eval=Symbol[#<>ToString[$ModuleNumber]]},eval/;True]&/@Cases[expr,sym_Symbol?(Not@*myValueQ):>SymbolName@Unevaluated[sym],{0,Infinity}])]
In[]:=
mDoPart[get[x_,y_],z_]:=bind[y,x|->z]
In[]:=
mDoPart[x_,y_]:=then[x,y]
In[]:=
mDo[x__]:=Fold[uniqueizeVars@mDoPart[#2,#1]&,Reverse[{x}]]
State Monad Code
State Monad Code
In[]:=
bind[state[h_],f_]:=state[s|->Replace[h[s],{a_,newState_}:>Replace[f[a],state[x_]:>x[newState]]]]
In[]:=
return[x_]:=state[{x,#}&]
In[]:=
runState[state[computation_],myState_List]:=computation[myState]
Push and Pop Definitions
Push and Pop Definitions
In[]:=
pushI[x_][{xs___}]:={{},{x,xs}}
In[]:=
push=state@*pushI;
In[]:=
popI[{x_,xs___}]:={x,{xs}}
In[]:=
pop=state[popI];
Stack Manipulation Setup
Stack Manipulation Setup
In[]:=
stackManip=mDo[push[3],pop,pop];
In[]:=
stackStuff=mDo[get[a,pop],If[a==5,push[5],mDo[push[3],push[8]]]];
In[]:=
moreStack=mDo[get[a,stackManip],If[a==100,stackStuff,return[{}]]];
Calculations
Calculations
In[]:=
runState[moreStack,{100,0,2,1,0}]
Out[]=
{{},{8,3,2,1,0}}
In[]:=
runState[moreStack,{100,5,2,1,0}]
Out[]=
{{},{5,2,1,0}}
In[]:=
runState[moreStack,{5,0,2,1,0}]
Out[]=
{{},{0,2,1,0}}
In[]:=
runState[moreStack,{5,5,2,1,0}]
Out[]=
{{},{5,2,1,0}}
CITE THIS NOTEBOOK
CITE THIS NOTEBOOK
Implementing Haskell's state monad and do notation in Wolfram
by Eric Parfitt
Wolfram Community, STAFF PICKS, June 13, 2025
https://community.wolfram.com/groups/-/m/t/3478726
by Eric Parfitt
Wolfram Community, STAFF PICKS, June 13, 2025
https://community.wolfram.com/groups/-/m/t/3478726