https://rosettacode.org/wiki/Monads/Writer_monad#M2000_Interpreter
I write 2 variants, one using tuple and lambda functions and lambda composition, and one using a class monad.
Variant 1
Module MonadWriter {
cr={
}
bind=lambda cr (a, b, c)->{
=(a, b+cr+" "+field$(c,17)+" : "+a)
}
Initial=lambda bind (v, txt as string="") ->{
=bind(v, txt, "Initial value")
}
SquareRoot=lambda bind (v, txt as string="") ->{
=bind(sqrt(v), txt, "Took square root")
}
AddedOne=lambda bind (v, txt as string="") ->{
=bind(v+1, txt, "Added one")
}
DividebyTwo=lambda bind (v, txt as string="") ->{
=bind(v/2, txt, "Divided by two")
}
Result=lambda bind (v, txt as string="") ->{
=bind(v, txt, "Result")
}
composition=lambda -> {
dim a()
a()=array([])
=lambda a() (x)-> {
ret=(x,"")
for i=0 to len(a())-1
ret=a(i)(!ret)
next
=ret
}
}
GoldenRatio=composition(Initial, SquareRoot, AddedOne, DividebyTwo, Result)
(val, ret)=GoldenRatio(5)
msg="The Golden Ratio is "
msg2="This was derived as follows:-"
report msg+val+{
}+msg2+ret
clipboard msg+val+{
}+msg2+ret
}
MonadWriter
Rem {
The Golden Ratio is 1.61803398874989
This was derived as follows:-
Initial value : 5
Took square root : 2.23606797749979
Added one : 3.23606797749979
Divided by two : 1.61803398874989
Result : 1.61803398874989
}
Variant 2 (same output)
The mystery from this program is; When we execute the value (value (.v) { }) function for all the "binds"? Look at function bind. We return m using =m. This not return immediate the object. Because m has a value part the interpreter call this part. We didn't get error (we didn't pass a value) because error happen if we didn't initialize the parameter, but the parameter is the member v (this.v or .v), which has a value 0. When we execute this function we process the strv and we return a copy of THIS, the current object (this never call the value part).
Module MonadWriter {
class monad {
private:
boolean err=true
v=0, t="", c=""
f=lambda->0
strV=""
cr={
}
public:
function strvalue() {
if .err then error "not intialised"
if .c<>"" then
=.c+.cr+.strV
else
=.strV
end if
}
function bind (m as monad) {
m.v<=.f(.v)
m.c<=.strvalue(.t)
m.err<=false
=m ' this call value () { }
}
value () { ' need () to mark "i want argument"
if not empty or not .err then
read .v ' .v has value so if empty interpreter pass this
.err<=false
.strV<=" "+field$(.t,17)+" : "+(.f(.v))
end if
=this
}
property value {
value {
link parent err, v, f to err, v, f
if err then error "not intialised"
value=f(v)
}
}
class:
module monad (.f as lambda, .t) {
}
}
Initial=monad(lambda (x)->x,"Initial value")
SquareRoot=monad(lambda (x)->Sqrt(x), "Took square root")
AddedOne=monad(lambda (x)->x+1, "Added one")
DividebyTwo=monad(lambda (x)->x/2, "Divided by two")
Result=initial(5).bind(SquareRoot).bind(AddedOne).bind(DividebyTwo).bind(monad(lambda (x)->x,"Result"))
val=Result.value
ret=Result.strvalue()
msg="The Golden Ratio is "
msg2="This was derived as follows:-"+{
}
report msg+val+{
}+msg2+ret
clipboard msg+val+{
}+msg2+ret
}
MonadWriter
Better code. I remove the value { } part so now we can pass the object monad without start the value {} part. I change it as Unit so first time we call Unit to pass the first value v. Then in each Bind we get the next object until we get values a tuple with the final value plus the log
Module MonadWriter {
class monad {
private:
boolean err=true
v=0, t="", c=""
f=lambda->0
strV=""
public:
function bind(m as monad) {
(m.v, m.c)=.values
=m.unit()
}
function unit(.v) {
.err<=false
.strV<=" "+field$(.t,17)+" : "+(.f(.v))
=this
}
property values {
value {
link parent err, v, f, c, strV to err, v, f, c, strV
if err then error "not intialised"
if c<>"" then
cr={
}
value=(f(v),c+cr+strV)
else
value=(f(v),strV)
end if
}
}=(,) ' empty tuple
class:
module monad (.f as lambda, .t) {
}
}
Initial=monad(lambda (x)->x,"Initial value")
SquareRoot=monad(lambda (x)->Sqrt(x), "Took square root")
AddedOne=monad(lambda (x)->x+1, "Added one")
DividebyTwo=monad(lambda (x)->x/2, "Divided by two")
Result=monad(lambda (x)->x,"Result")
(val, ret)=initial.unit(5).bind(SquareRoot).bind(AddedOne).bind(DividebyTwo).bind(Result).values
msg="The Golden Ratio is "
msg2="This was derived as follows:-"+{
}
report msg+val+{
}+msg2+ret
clipboard msg+val+{
}+msg2+ret
}
MonadWriter
Δεν υπάρχουν σχόλια:
Δημοσίευση σχολίου
You can feel free to write any suggestion, or idea on the subject.