Implementación de la mónada de estado y la notación “do” de Haskell en Wolfram

por Eric Parfitt
Este cuaderno es una traducción al español del artículo de la Comunidad Wolfram “Implementing Haskell's state monad and do notation in Wolfram” producido con ayuda de un LLM y verificado por un traductor profesional

Introducción

Recientemente he estado aprendiendo Haskell y decidí ver si podía implementar mónadas en Wolfram Language. Para probar esto, también he implementado una versión de la notación “do” de Haskell y la mónada de “estado”.

Problemas

Un problema con el que me encontré es que Wolfram Language hace lo siguiente:
Function
In[]:=
foo[f_]:=x|->f[x]
In[]:=
Nest[foo,b,3]
Out[]=
Function[x$,Function[x$,Function[x$,b[x$]][x$]][x$]]
Lo cual terminó causando problemas para mi función cuando las personas usaron la sintaxis “” para definir funciones en sus mónadas. Se puede evitar esto definiendo foo de manera equivalente como
In[]:=
foo[f_]:=f[#]&
In[]:=
Nest[foo,b,3]
Out[]=
((b[#1]&)[#1]&)[#1]&
(la respuesta que quería) pero quiero que el usuario de las mónadas no tenga que preocuparse por qué sintaxis específica utilizar para definir funciones, y que podría obtener la respuesta equivocada si utiliza la sintaxis “incorrecta”. Así que Kurt Gimbel me ayudó con esa parte, y realizó casi todo el diseño de la función “uniquizeVars”, la cual asegura que las funciones anidadas siempre tengan variables únicas cuando se supone que deben serlo. Si uno evita usar la sintaxis “” o Function con variables nombradas, puede simplemente prescindir de esa función, y la definición de las mónadas sería un poco más elegante. Pero yo quería esa característica, así que aquí está.
​
A continuación, defino el código para la notación “do” y la mónada “state”, y luego configuro y ejecuto algunos cálculos compuestos con estado que implican operaciones de push y pop, utilizando la notación “do” definida.

Código de notación “Do”

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}]]

Código de la mónada de estado

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]

Definiciones push y pop

In[]:=
pushI[x_][{xs___}]:={{},{x,xs}}
In[]:=
push=state@*pushI;
In[]:=
popI[{x_,xs___}]:={x,{xs}}
In[]:=
pop=state[popI];

Configuración de manipulación de pila

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[{}]]];

Cálculos

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 ESTE CUADERNO

Implementación de la mónada de estado y la notación “do” de Haskell en Wolfram​
por Eric Parfitt​
Comunidad Wolfram, STAFF PICKS, 13 de junio de 2025
​https://community.wolfram.com/groups/-/m/t/3478726