Monads/Writer monad: Difference between revisions

Added FreeBASIC
(Added C++ implementation)
(Added FreeBASIC)
 
(17 intermediate revisions by 9 users not shown)
Line 13:
=={{header|ALGOL 68}}==
{{Trans|Go}}
<langsyntaxhighlight lang="algol68">BEGIN
MODE MWRITER = STRUCT( LONG REAL value
, STRING log
Line 38:
print( ( newline, "This was derived as follows:-", newline ) );
print( ( log OF mw2 ) )
END</langsyntaxhighlight>
{{out}}
<pre>
Line 58:
More than a light-weight scripting language is really likely to need, but a way of stretching it a bit, and understanding its relationship to other languages. What AppleScript mainly lacks (apart from a well-developed library, and introspective records/dictionaries which know what keys/fields they have), is a coherent type of first class (and potentially anonymous) function. To get first class objects, we have to wrap 2nd class handlers in 1st class scripts.
 
<langsyntaxhighlight AppleScriptlang="applescript">-- WRITER MONAD FOR APPLESCRIPT
 
-- How can we compose functions which take simple values as arguments
Line 176:
end call
end script
end sBind</langsyntaxhighlight>
 
{{Out}}
Line 187:
divided by two -> 1.61803398875"
}</pre>
 
=={{header|ATS}}==
The entry for [[#Haskell|Haskell]] inspired me to do such things as add a <code>&gt;=&gt;</code> operator, and to use <code>return</code> as a name for the ''unit'' operation. But notice that I write <code>return&lt;double&gt;</code>. The template system, for whatever reason, could not infer the type, if I left out the template parameter. It did not signal an error, but instead produced C code that could not be compiled. This kind of behavior is common with the Postiats implementation of ATS, and must be gotten used to.
 
(''Footnote'': Sometimes the template system will produce C code that ''can'' be compiled but does not function correctly! No doubt the template system can be made more shipshape, but it is what it is. In any case, one then goes through the code and fills in elided template parameters, until the code works.)
 
<syntaxhighlight lang="ats">
#include "share/atspre_staload.hats"
 
%{^
#include <math.h>
%}
 
#define NIL list_nil ()
#define :: list_cons
 
(* The log is a list of strings. For efficiency, it is ordered
most-recent-first. The static value "n" represents the number of
entries in the log. (It exists and is used only during the
typechecking phase.) *)
datatype Writer (a : t@ype+, n : int) =
| Writer of (a, list (string, n))
typedef Writer (a : t@ype+) = [n : int] Writer (a, n)
 
prfn
lemma_Writer_param {a : t@ype}
{n : int}
(m : Writer (a, n))
:<prf> [0 <= n] void =
let
val+ Writer (_, log) = m
in
lemma_list_param log
end
 
fn {a : t@ype}
unit_Writer (x : a) : Writer (a, 1) =
let
val msg = string_append ("unit_Writer (",
tostring_val<a> x, ")")
val msg = strptr2string msg
in
Writer (x, msg :: NIL)
end
 
overload return with unit_Writer
 
fn {a, b : t@ype}
bind_Writer {n : int}
(m : Writer (a, n),
f : a -<cloref1> Writer b)
: [n1 : int | n <= n1] Writer (b, n1) =
let
val+ Writer (x, log) = m
val y = f (x)
prval () = lemma_Writer_param y
val+ Writer (y, entries) = y
in
Writer (y, list_append (entries, log))
end
 
infixl 0 >>=
overload >>= with bind_Writer
 
fn {a, b, c : t@ype}
compose_Writer (f : a -<cloref1> Writer b,
g : b -<cloref1> Writer c)
: a -<cloref1> Writer c =
lam m => f m >>= g
 
infixl 0 >=>
overload >=> with compose_Writer
 
(* "make_Writer_closure_from_fun" wraps an ordinary function from a to
b, resulting in a closure that will produce exactly one log
entry. *)
fn {a, b : t@ype}
make_Writer_closure_from_fun (func : a -> b,
make_msg : (a, b) -<cloref1> string)
: a -<cloref1> Writer (b, 1) =
lam x =>
let
val y = func x
in
Writer (y, make_msg (x, y) :: NIL)
end
 
overload make_Writer_closure with make_Writer_closure_from_fun
 
(* A note regarding "root": interfaces to the C math library are
available, even within the Postiats distribution, but I shall
simply make a foreign function call to sqrt(3). The Postiats
prelude itself provides no (or very little) interface to libm. *)
fn root (x : double) : double = $extfcall (double, "sqrt", x)
fn addOne (x : double) : double = succ x
fn half (x : double) : double = 0.5 * x
 
fn {a, b : t@ype}
make_logging (func : a -> b,
notation : string)
: a -<cloref1> Writer (b, 1) =
let
fn
make_msg (x : a, y : b) :<cloref1> string =
let
val msg = string_append ("(", tostring_val<a> x,
" |> ", notation, ") --> ",
tostring_val<b> y)
in
strptr2string msg
end
in
make_Writer_closure<a,b> (func, make_msg)
end
 
val logging_root = make_logging<double,double> (root, "sqrt")
val logging_addOne = make_logging<double,double> (addOne, "(+ 1.0)")
val logging_half = make_logging<double,double> (half, "(0.5 *)")
 
val the_big_whatchamacallit =
logging_root >=> logging_addOne >=> logging_half
 
fn
print_log (log : List string) : void =
let
fun
loop (lst : List0 string) : void =
case+ lst of
| NIL => ()
| hd :: tl =>
begin
println! (" ", hd);
loop tl
end
 
prval () = lemma_list_param log
in
loop (list_vt2t (list_reverse log))
end
 
implement
main0 () =
let
val x = 5.0
val m = return<double> x
val+ Writer (y, log) = m >>= the_big_whatchamacallit
in
println! ("(1 + sqrt(", x : double, "))/2 = ", y : double);
println! ("log:");
print_log log
end
</syntaxhighlight>
 
{{out}}
<pre>$ patscc -std=gnu2x -g -O2 -DATS_MEMALLOC_GCBDW writer_monad_ats.dats -lgc -lm && ./a.out
(1 + sqrt(5.000000))/2 = 1.618034
log:
unit_Writer (5.000000)
(5.000000 |> sqrt) --> 2.236068
(2.236068 |> (+ 1.0)) --> 3.236068
(3.236068 |> (0.5 *)) --> 1.618034</pre>
 
=={{header|C++}}==
<langsyntaxhighlight lang="cpp">#include <cmath>
#include <iostream>
#include <string>
Line 215 ⟶ 376:
 
// Define a function to create writer monads from the simple functions
auto WriterMakeWriter = [](auto f, string message)
{
return [=](double x){return LoggingMonad(f(x), message);};
Line 221 ⟶ 382:
 
// Derive writer versions of the simple functions
auto writerRoot = WriterMakeWriter(Root, "Taking square root");
auto writerAddOne = WriterMakeWriter(AddOne, "Adding 1");
auto writerHalf = WriterMakeWriter(Half, "Dividing by 2");
 
 
Line 232 ⟶ 393:
cout << result.Log << "\nResult: " << result.Value;
}
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 241 ⟶ 402:
Result: 1.61803
</pre>
 
 
=={{header|EchoLisp}}==
Our monadic Writer elements will be pairs (string . value), where string is the log string.
 
<langsyntaxhighlight lang="scheme">
(define (Writer.unit x (log #f))
(if log (cons log x)
Line 289 ⟶ 449:
add-one → 2
half → 1
</syntaxhighlight>
</lang>
 
=={{header|FreeBASIC}}==
{{trans|Go}}
<syntaxhighlight lang="vbnet">Type mwriter
value As Double
log_ As String
End Type
 
Function Unit(v As Double, s As String) As mwriter
Dim As mwriter mw
mw.value = v
mw.log_ = " " & s & ": " & Str(v) & Chr(10)
Return mw
End Function
 
Function Root(mw As mwriter) As mwriter
mw.value = Sqr(mw.value)
mw.log_ = mw.log_ & " Took square Root: " & Str(mw.value) & Chr(10)
Return mw
End Function
 
Function addOne(mw As mwriter) As mwriter
mw.value = mw.value + 1
mw.log_ = mw.log_ & " Added one : " & Str(mw.value) & Chr(10)
Return mw
End Function
 
Function Half(mw As mwriter) As mwriter
mw.value = mw.value / 2
mw.log_ = mw.log_ & " Divided by two : " & Str(mw.value) & Chr(10)
Return mw
End Function
 
Dim As mwriter mw1
mw1 = Unit(5, "Initial value ")
mw1 = Root(mw1)
mw1 = addOne(mw1)
mw1 = Half(mw1)
Print "The Golden Ratio is "; mw1.value
Print !"\nThis was derived as follows:-"
Print mw1.log_
 
Sleep</syntaxhighlight>
{{out}}
<pre>The Golden Ratio is 1.618033988749895
 
This was derived as follows:-
Initial value : 5
Took square Root: 2.23606797749979
Added one : 3.23606797749979
Divided by two : 1.618033988749895</pre>
 
=={{header|F_Sharp|F#}}==
<syntaxhighlight lang="fsharp">
// Monads/Writer monad . Nigel Galloway: July 20th., 2022
type Riter<'n>=Riter of 'n * List<string>
let eval=function |Riter(n,g)->(n,g)
let compose f=function |Riter(n,g)->let n,l=eval(f n) in Riter(n,List.append g l)
let initV n=Riter(n,[sprintf "Initial Value %f" n])
let sqrt n=Riter(sqrt n,["Took square root"])
let div n g=Riter(n/g,[sprintf "Divided by %f" n])
let add n g=Riter(n+g,[sprintf "Added %f" n])
let result,log=eval((initV>>compose sqrt>>compose(add 1.0)>>compose(div 2.0))5.0)
log|>List.iter(printfn "%s")
printfn "Final value = %f" result
</syntaxhighlight>
{{out}}
<pre>
Initial Value 5.000000
Took square root
Added 1.000000
Divided by 2.000000
Final value = 0.618034
</pre>
 
=={{header|Factor}}==
Factor comes with an implementation of Haskell-style monads in the <code>monads</code> vocabulary.
{{works with|Factor|0.99 2019-10-06}}
<langsyntaxhighlight lang="factor">USING: kernel math math.functions monads prettyprint ;
FROM: monads => do ;
 
Line 302 ⟶ 536:
[ 1 + "added one, " <writer> ]
[ 2 / "divided by two." <writer> ]
} do .</langsyntaxhighlight>
{{out}}
<pre>
Line 315 ⟶ 549:
=={{header|Go}}==
{{trans|Kotlin}}
<langsyntaxhighlight lang="go">package main
 
import (
Line 355 ⟶ 589:
fmt.Println("\nThis was derived as follows:-")
fmt.Println(mw2.log)
}</langsyntaxhighlight>
 
{{out}}
Line 373 ⟶ 607:
 
Making a logging version of functions (unfortunately, if we use the built-in writer monad we cannot get the values into the logs when binding):
<langsyntaxhighlight lang="haskell">import Control.Monad.Trans.Writer
import Control.Monad ((>=>))
 
Line 385 ⟶ 619:
halfOfAddOneOfRoot = logRoot >=> logAddOne >=> logHalf
 
main = print $ runWriter (halfOfAddOneOfRoot 5)</langsyntaxhighlight>
 
{{Out}}
Line 397 ⟶ 631:
Based on javascript implementation:
 
<langsyntaxhighlight Jlang="j">root=: %:
incr=: >:
half=: -:
Line 423 ⟶ 657:
loggingCompose=: dyad define
;(dyad def '<x`:6 loggingBind;y')/x,<loggingUnit y
)</langsyntaxhighlight>
 
Task example:
 
<langsyntaxhighlight Jlang="j"> 0{::Lhalf`Lincr`Lroot loggingCompose 5
1.61803
1{::Lhalf`Lincr`Lroot loggingCompose 5
Line 433 ⟶ 667:
obtained square root -> 2.23607
added 1 -> 3.23607
divided by 2 -> 1.61803</langsyntaxhighlight>
 
=={{header|Java}}==
<syntaxhighlight lang="java">
import java.util.function.Function;
 
public final class MonadWriter {
 
public static void main(String[] aArgs) {
Monad<Double> initial = Monad.unit(5.0, "Initial value");
Monad<Double> result = initial.bind(MonadWriter::root).bind(MonadWriter::addOne).bind(MonadWriter::half);
System.out.println("The Golden Ratio is " + result.getValue() + System.lineSeparator());
System.out.println("This was derived as follows:" + System.lineSeparator() + result.getText());
}
private static Monad<Double> root(double aD) {
return Monad.unit(Math.sqrt(aD), "Took square root");
}
 
private static Monad<Double> addOne(double aD) {
return Monad.unit(aD + 1.0, "Added one");
}
 
private static Monad<Double> half(double aD) {
return Monad.unit(aD / 2.0, "Divided by two");
}
}
final class Monad<T> {
public static <T> Monad<T> unit(T aValue, String aText) {
return new Monad<T>(aValue, aText);
}
public Monad<T> bind(Function<T, Monad<T>> aFunction) {
Monad<T> monad = aFunction.apply(value);
monad.text = text + monad.text;
return monad;
}
public T getValue() {
return value;
}
public String getText() {
return text;
}
private Monad(T aValue, String aText) {
value = aValue;
text = String.format("%-21s%s%n", " " + aText, ": " + aValue);
}
private T value;
private String text;
}
</syntaxhighlight>
{{ out }}
<pre>
The Golden Ratio is 1.618033988749895
 
This was derived as follows:
Initial value : 5.0
Took square root : 2.23606797749979
Added one : 3.23606797749979
Divided by two : 1.618033988749895
</pre>
 
=={{header|JavaScript}}==
Line 439 ⟶ 741:
===ES5===
 
<langsyntaxhighlight JavaScriptlang="javascript">(function () {
'use strict';
 
Line 525 ⟶ 827:
 
return half_of_addOne_of_root(5);
})();</langsyntaxhighlight>
 
{{Out}}
Line 540 ⟶ 842:
From Javascript ES5 entry.
 
<langsyntaxhighlight lang="javascript">'use strict';
 
/* writer monad, in Jsish */
Line 642 ⟶ 944:
divided by 2 -> 1.61803398874989
=!EXPECTEND!=
*/</langsyntaxhighlight>
 
{{out}}
Line 649 ⟶ 951:
 
=={{header|Julia}}==
<langsyntaxhighlight lang="julia">struct Writer x::Real; msg::String; end
 
Base.show(io::IO, w::Writer) = print(io, w.msg, ": ", w.x)
Line 666 ⟶ 968:
println("$a => $b => $c")
println(bind(f2, "after plus 8", bind(f1, "after times 7", unit(3, "after intialization"))))
</langsyntaxhighlight>{{out}}
<pre>
after intialization: 3 => after intialization, after times 7: 21 => after intialization, after times 7, after plus 8: 29
Line 673 ⟶ 975:
 
=={{header|Kotlin}}==
<langsyntaxhighlight lang="scala">// version 1.2.10
 
import kotlin.math.sqrt
Line 703 ⟶ 1,005:
println("The Golden Ratio is ${fv.value}")
println("\nThis was derived as follows:-\n${fv.log}")
}</langsyntaxhighlight>
 
{{out}}
Line 717 ⟶ 1,019:
 
=={{header|Nim}}==
<langsyntaxhighlight Nimlang="nim">from math import sqrt
from sugar import `=>`, `->`
 
Line 736 ⟶ 1,038:
 
echo 5.doneWith.logRoot.logAddOne.logHalf
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 744 ⟶ 1,046:
=={{header|Perl}}==
{{trans|Raku}}
<langsyntaxhighlight Perllang="perl"># 20200704 added Perl programming solution
 
package Writer;
Line 772 ⟶ 1,074:
 
print Unit(5, "Initial value")->Bind(\&root)->Bind(\&addOne)->Bind(\&half)->[1];
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 782 ⟶ 1,084:
 
=={{header|Phix}}==
<!--<syntaxhighlight lang="phix">(phixonline)-->
<lang Phix>function bind(object m, integer f)
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
return f(m)
<span style="color: #008080;">function</span> <span style="color: #000000;">bind</span><span style="color: #0000FF;">(</span><span style="color: #004080;">object</span> <span style="color: #000000;">m</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">integer</span> <span style="color: #000000;">f</span><span style="color: #0000FF;">)</span>
end function
<span style="color: #008080;">return</span> <span style="color: #000000;">f</span><span style="color: #0000FF;">(</span><span style="color: #000000;">m</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
function unit(object m)
return m
<span style="color: #008080;">function</span> <span style="color: #000000;">unit</span><span style="color: #0000FF;">(</span><span style="color: #004080;">object</span> <span style="color: #000000;">m</span><span style="color: #0000FF;">)</span>
end function
<span style="color: #008080;">return</span> <span style="color: #000000;">m</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
function root(sequence al)
{atom a, string lg} = al
<span style="color: #008080;">function</span> <span style="color: #000000;">root</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">al</span><span style="color: #0000FF;">)</span>
atom res = sqrt(a)
<span style="color: #0000FF;">{</span><span style="color: #004080;">atom</span> <span style="color: #000000;">a</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">string</span> <span style="color: #000000;">lg</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">al</span>
return {res,lg&sprintf("took root: %f -> %f\n",{a,res})}
<span style="color: #004080;">atom</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">sqrt</span><span style="color: #0000FF;">(</span><span style="color: #000000;">a</span><span style="color: #0000FF;">)</span>
end function
<span style="color: #008080;">return</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">res</span><span style="color: #0000FF;">,</span><span style="color: #000000;">lg</span><span style="color: #0000FF;">&</span><span style="color: #7060A8;">sprintf</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"took root: %f -&gt; %f\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">a</span><span style="color: #0000FF;">,</span><span style="color: #000000;">res</span><span style="color: #0000FF;">})}</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
function addOne(sequence al)
{atom a, string lg} = al
<span style="color: #008080;">function</span> <span style="color: #000000;">addOne</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">al</span><span style="color: #0000FF;">)</span>
atom res = a + 1
<span style="color: #0000FF;">{</span><span style="color: #004080;">atom</span> <span style="color: #000000;">a</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">string</span> <span style="color: #000000;">lg</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">al</span>
return {res,lg&sprintf("added one: %f -> %f\n",{a,res})}
<span style="color: #004080;">atom</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">a</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">1</span>
end function
<span style="color: #008080;">return</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">res</span><span style="color: #0000FF;">,</span><span style="color: #000000;">lg</span><span style="color: #0000FF;">&</span><span style="color: #7060A8;">sprintf</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"added one: %f -&gt; %f\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">a</span><span style="color: #0000FF;">,</span><span style="color: #000000;">res</span><span style="color: #0000FF;">})}</span>
 
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
function half(sequence al)
{atom a, string lg} = al
<span style="color: #008080;">function</span> <span style="color: #000000;">half</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">al</span><span style="color: #0000FF;">)</span>
atom res = a / 2
<span style="color: #0000FF;">{</span><span style="color: #004080;">atom</span> <span style="color: #000000;">a</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">string</span> <span style="color: #000000;">lg</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">al</span>
return {res,lg&sprintf("halved it: %f -> %f\n",{a,res})}
<span style="color: #004080;">atom</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">a</span> <span style="color: #0000FF;">/</span> <span style="color: #000000;">2</span>
end function
<span style="color: #008080;">return</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">res</span><span style="color: #0000FF;">,</span><span style="color: #000000;">lg</span><span style="color: #0000FF;">&</span><span style="color: #7060A8;">sprintf</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"halved it: %f -&gt; %f\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">a</span><span style="color: #0000FF;">,</span><span style="color: #000000;">res</span><span style="color: #0000FF;">})}</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
printf(1,"%f obtained by\n%s", bind(bind(bind({5,""},root),addOne),half))</lang>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%f obtained by\n%s"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">bind</span><span style="color: #0000FF;">(</span><span style="color: #000000;">bind</span><span style="color: #0000FF;">(</span><span style="color: #000000;">bind</span><span style="color: #0000FF;">({</span><span style="color: #000000;">5</span><span style="color: #0000FF;">,</span><span style="color: #008000;">""</span><span style="color: #0000FF;">},</span><span style="color: #000000;">root</span><span style="color: #0000FF;">),</span><span style="color: #000000;">addOne</span><span style="color: #0000FF;">),</span><span style="color: #000000;">half</span><span style="color: #0000FF;">))</span>
<!--</syntaxhighlight>-->
{{out}}
<pre>
Line 818 ⟶ 1,123:
 
=={{header|PHP}}==
<langsyntaxhighlight lang="php">class WriterMonad {
 
/** @var mixed */
Line 861 ⟶ 1,166:
 
print "The Golden Ratio is: {$result->value()}\n";
print join("\n", $result->logs());</langsyntaxhighlight>
 
{{out}}
Line 874 ⟶ 1,179:
=={{header|Python}}==
 
<syntaxhighlight lang="python">
<lang python>"""A Writer Monad. Requires Python >= 3.7 for type hints."""
"""A Writer Monad. Requires Python >= 3.7 for type hints."""
from __future__ import annotations
 
Line 881 ⟶ 1,187:
import os
 
from typing import Any
from typing import Callable
from typing import Generic
Line 890 ⟶ 1,195:
 
T = TypeVar("T")
U = TypeVar("U")
 
 
Line 901 ⟶ 1,207:
self.msgs = list(f"{msg}: {self.value}" for msg in msgs)
 
def bind(self, func: Callable[[T], Writer[AnyU]]) -> Writer[AnyU]:
writer = func(self.value)
return Writer(writer, *self.msgs)
 
def __rshift__(self, func: Callable[[T], Writer[AnyU]]) -> Writer[AnyU]:
return self.bind(func)
 
Line 915 ⟶ 1,221:
 
 
def lift(func: Callable[[T], U], msg: str) -> Callable[[AnyT], Writer[AnyU]]:
"""Return a writer monad version of the simple function `func`."""
 
@functools.wraps(func)
def wrapped(value: T) -> Writer[U]:
return Writer(func(value), msg)
 
Line 927 ⟶ 1,233:
if __name__ == "__main__":
square_root = lift(math.sqrt, "square root")
 
add_one = lift(lambda x: x + 1, "add one")
add_one: Callable[[Union[int, float]], Writer[Union[int, float]]] = lift(
half = lift(lambda x: x / 2, "div two")
lambda x: x + 1, "add one"
)
 
half: Callable[[Union[int, float]], Writer[float]] = lift(
lambda x: x / 2, "div two"
)
 
print(Writer(5, "initial") >> square_root >> add_one >> half)
</syntaxhighlight>
</lang>
 
{{out}}
Line 945 ⟶ 1,257:
Basic semantic borrowed from the Monads/List monad entry
{{trans|Go}}
<syntaxhighlight lang="raku" perl6line># 20200508 Raku programming solution
 
class Writer { has Numeric $.value ; has Str $.log }
Line 962 ⟶ 1,274:
sub half(\v) { Unit v/2, "Divided by two" }
 
say Unit(5, "Initial value").&Bind(&root).&Bind(&addOne).&Bind(&half).log;</langsyntaxhighlight>
{{out}}
<pre>Initial value : 5.000000000000
Line 968 ⟶ 1,280:
Added one : 3.236067977500
Divided by two : 1.618033988750
</pre>
 
=={{header|Ruby}}==
 
<syntaxhighlight lang="ruby"># 20220720 Ruby programming solution
class Writer
attr_reader :value, :log
 
def initialize(value, log = "New")
@value = value
if value.is_a? Proc
@log = log
else
@log = log + ": " + @value.to_s
end
end
 
def self.unit(value, log)
Writer.new(value, log)
end
 
def bind(mwriter)
new_value = mwriter.value.call(@value)
new_log = @log + "\n" + mwriter.log
self.class.new(new_value, new_log)
end
end
 
lam_sqrt = ->(number) { Math.sqrt(number) }
lam_add_one = ->(number) { number + 1 }
lam_half = ->(number) { number / 2.0 }
 
sqrt = Writer.unit( lam_sqrt, "Took square root")
add_one = Writer.unit( lam_add_one, "Added one")
half = Writer.unit( lam_half, "Divided by 2")
 
m1 = Writer.unit(5, "Initial value")
m2 = m1.bind(sqrt).bind(add_one).bind(half)
 
puts "The final value is #{m2.value}\n\n"
puts "This value was derived as follows:"
puts m2.log
</syntaxhighlight>
 
{{out}}
<pre>
The final value is 1.618033988749895
 
This value was derived as follows:
Initial value: 5
Took square root: 2.23606797749979
Added one: 3.23606797749979
Divided by 2: 1.618033988749895
</pre>
 
=={{header|Scheme}}==
{{works with|Gauche Scheme|0.9.12}}
{{works with|CHICKEN Scheme|5.3.0}}
 
The program is written in R7RS-small Scheme. For CHICKEN you will need the <code>r7rs</code> egg.
 
<syntaxhighlight lang="scheme">
(define-library (monad base)
(export make-monad monad? monad-identifier
monad-object monad-additional
>>= >=>)
(import (scheme base)
(scheme case-lambda))
(begin
 
(define-record-type <monad>
(make-monad identifier bind object additional)
monad?
(identifier monad-identifier)
(bind monad-bind)
(object monad-object)
(additional monad-additional))
 
(define >>=
(case-lambda
((m f) ((monad-bind m) m f))
((m f . g*) (apply >>= (cons (>>= m f) g*)))))
 
(define >=>
(case-lambda
((f g) (lambda (x) (>>= (f x) g)))
((f g . h*) (apply >=> (cons (>=> f g) h*)))))
 
)) ;; end library
 
(define-library (monad perform)
(export perform)
(import (scheme base)
(monad base))
(begin
 
(define-syntax perform
;; "do" is already one of the loop syntaxes, so I call this
;; syntax "perform" instead.
(syntax-rules (<-)
((perform (x <- action) clause clause* ...)
(>>= action (lambda (x) (perform clause clause* ...))))
((perform action)
action)
((perform action clause clause* ...)
(action (perform clause clause* ...)))))
 
)) ;; end library
 
(define-library (monad writer-monad)
(export make-writer-monad writer-monad?)
(import (scheme base)
(monad base))
(begin
 
;; The messages are a list, most recent message first, of whatever
;; data f decides to log.
(define (make-writer-monad object messages)
(define (bind m f)
(let ((ym (f (monad-object m))))
(let ((old-messages (monad-additional m))
(new-messages (monad-additional ym))
(y (monad-object ym)))
(make-monad 'writer-monad bind y
(append new-messages old-messages)))))
(unless (or (null? messages) (pair? messages))
;;
;; I do not actually test whether the list is proper, because
;; to do so would be inefficient.
;;
;; The R7RS-small test for properness of a list is called
;; "list?" (and the report says something tendentious in
;; defense of this name, but really it is simply historical
;; usage). The SRFI-1 procedure, by constrast, is called
;; "proper-list?".
;;
(error "should be a proper list" messages))
(make-monad 'writer-monad bind object messages))
 
(define (writer-monad? object)
(and (monad? object)
(eq? (monad-identifier object) 'writer-monad)))
 
)) ;; end library
 
(import (scheme base)
(scheme inexact)
(scheme write)
(monad base)
(monad perform)
(monad writer-monad))
 
(define root sqrt)
(define (addOne x) (+ x 1))
(define (half x) (/ x 2))
 
(define-syntax make-logging
(syntax-rules ()
((_ proc)
(lambda (x)
(define (make-msg x y) (list x 'proc y))
(let ((y (proc x)))
(make-writer-monad y (list (make-msg x y))))))))
 
(define logging-root (make-logging root))
(define logging-addOne (make-logging addOne))
(define logging-half (make-logging half))
 
(define (display-messages messages)
(if (writer-monad? messages)
(display-messages (monad-additional messages))
(begin
(display " messages:")
(newline)
(let loop ((lst (reverse messages)))
(when (pair? lst)
(display " ")
(write (car lst))
(newline)
(loop (cdr lst)))))))
 
(display "---------------") (newline)
(display "Using just >>=") (newline)
(display "---------------") (newline)
(define result
(>>= (make-writer-monad 5 '((new writer-monad 5)))
logging-root logging-addOne logging-half))
(display " (1 + sqrt(5))/2 = ")
(write (monad-object result)) (newline)
(display-messages result)
 
(newline)
 
(display "------------------") (newline)
(display "Using >>= and >=>") (newline)
(display "------------------") (newline)
(define result
(>>= (make-writer-monad 5 '((new writer-monad 5)))
(>=> logging-root logging-addOne logging-half)))
(display " (1 + sqrt(5))/2 = ")
(write (monad-object result)) (newline)
(display-messages result)
 
(newline)
 
(display "-----------------------") (newline)
(display "Using 'perform' syntax") (newline)
(display "-----------------------") (newline)
(define result
(perform (x <- (make-writer-monad 5 '((new writer-monad 5))))
(x <- (logging-root x))
(x <- (logging-addOne x))
(logging-half x)))
(display " (1 + sqrt(5))/2 = ")
(write (monad-object result)) (newline)
(display-messages result)
</syntaxhighlight>
 
{{out}}
Compile and run with <pre>gosh -r7 writer_monad_r7rs.scm</pre> or <pre>csc -O5 -X r7rs -R r7rs writer_monad_r7rs.scm && ./writer_monad_r7rs</pre>
 
(I use the high optimization level <code>-O5</code> to check I have done nothing to impede such optimization.)
 
The result is computed in three different notations. The <code>perform</code> syntax is something that looks like Haskell's <code>do</code> syntax. (The name <code>do</code> is already used as the Scheme and Common Lisp name for a kind of for-loop.)
 
Notice that the <code>&gt;&gt;=</code> and <code>&gt;-&gt;</code> are ordinary "prefix" procedures, rather than infix operators. One might think this would make them very difficult to write with, but a Scheme procedure can be made to recursively perform a chain of operations, so that you will need to write the procedure name only once. I have made <code>&gt;&gt;=</code> and <code>&gt;-&gt;</code> work that way.
 
<pre>
---------------
Using just >>=
---------------
(1 + sqrt(5))/2 = 1.61803398874989
messages:
(new writer-monad 5)
(5 root 2.23606797749979)
(2.23606797749979 addOne 3.23606797749979)
(3.23606797749979 half 1.61803398874989)
 
------------------
Using >>= and >=>
------------------
(1 + sqrt(5))/2 = 1.61803398874989
messages:
(new writer-monad 5)
(5 root 2.23606797749979)
(2.23606797749979 addOne 3.23606797749979)
(3.23606797749979 half 1.61803398874989)
 
-----------------------
Using 'perform' syntax
-----------------------
(1 + sqrt(5))/2 = 1.61803398874989
messages:
(new writer-monad 5)
(5 root 2.23606797749979)
(2.23606797749979 addOne 3.23606797749979)
(3.23606797749979 half 1.61803398874989)
</pre>
 
Line 973 ⟶ 1,542:
{{trans|Go}}
{{libheader|Wren-fmt}}
<langsyntaxhighlight ecmascriptlang="wren">import "./fmt" for Fmt
 
class Mwriter {
Line 1,002 ⟶ 1,571:
System.print("The Golden Ratio is %(mw2.value)")
System.print("\nThis was derived as follows:-")
System.print(mw2.log)</langsyntaxhighlight>
 
{{out}}
Line 1,017 ⟶ 1,586:
=={{header|zkl}}==
{{trans|EchoLisp}}
<langsyntaxhighlight lang="zkl">class Writer{
fcn init(x){ var X=x, logText=Data(Void," init \U2192; ",x.toString()) }
fcn unit(text) { logText.append(text); self }
Line 1,027 ⟶ 1,596:
fcn half{ lift('/(2),"half") }
fcn inc { lift('+(1),"inc") }
}</langsyntaxhighlight>
<langsyntaxhighlight lang="zkl">Writer(5.0).root().inc().half().println();</langsyntaxhighlight>
{{out}}
<pre>
Line 1,037 ⟶ 1,606:
half → 1.61803
</pre>
<langsyntaxhighlight lang="zkl">w:=Writer(5.0);
Utils.Helpers.fcomp(w.half,w.inc,w.root)(w).println(); // half(inc(root(w)))</langsyntaxhighlight>
{{out}}
<pre>
Line 1,048 ⟶ 1,617:
</pre>
Use bind to add functions to an existing Writer:
<langsyntaxhighlight lang="zkl">w:=Writer(5.0);
root,inc,half := w.bind(fcn(x){ x.sqrt() },"root"), w.bind('+(1),"+ 1"), w.bind('/(2),"/ 2");
root(); inc(); half(); w.println();</langsyntaxhighlight>
{{out}}
<pre>
2,122

edits