The Writer monad is a programming design pattern which makes it possible to compose functions which return their result values paired with a log string. The final result of a composed function yields both a value, and a concatenation of the logs from each component function application.

Demonstrate in your programming language the following:

Construct a Writer monad by writing the 'bind' function and the 'unit' (sometimes known as 'return') function for that monad (or just use what the language already provides)

Write three simple functions: root, addOne, and half

Derive Writer monad versions of each of these functions

Apply a composition of the Writer versions of root, addOne, and half to the integer 5, deriving both a value for the Golden Ratio φ, and a concatenated log of the function applications (starting with the initial value, and followed by the application of root, etc.)

ALGOL 68

BEGIN
    MODE MWRITER = STRUCT( LONG REAL value
                         , STRING    log
                         );
    PRIO BIND = 9;
    OP   BIND = ( MWRITER m, PROC( LONG REAL )MWRITER f )MWRITER:
    (    MWRITER n := f( value OF m );
         log OF n  := log OF m + log OF n;
         n
    );

    OP   LEN     = ( STRING s )INT: ( UPB s + 1 ) - LWB s;
    PRIO PAD     = 9;
    OP   PAD     = ( STRING s, INT width )STRING: IF LEN s >= width THEN s ELSE s + ( width - LEN s ) * " " FI;

    PROC unit    = ( LONG REAL v, STRING s )MWRITER: ( v, "  " + s PAD 17 + ":" + fixed( v, -19, 15 ) + REPR 10 );
 
    PROC root    = ( LONG REAL v )MWRITER: unit( long sqrt( v ), "Took square root" );
    PROC add one = ( LONG REAL v )MWRITER: unit( v+1, "Added one" );
    PROC half    = ( LONG REAL v )MWRITER: unit( v/2, "Divided by two" );
 
    MWRITER mw2 := unit( 5, "Initial value" ) BIND root BIND add one BIND half;
    print( ( "The Golden Ratio is", fixed( value OF mw2, -19, 15 ), newline ) );
    print( ( newline, "This was derived as follows:-", newline ) );
    print( ( log OF mw2 ) )
END

The Golden Ratio is  1.618033988749895

This was derived as follows:-
  Initial value    :  5.000000000000000
  Took square root :  2.236067977499790
  Added one        :  3.236067977499790
  Divided by two   :  1.618033988749895

AppleScript

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.

-- WRITER MONAD FOR APPLESCRIPT

-- How can we compose functions which take simple values as arguments
-- but return an output value which is paired with a log string ?

-- We can prevent functions which expect simple values from choking 
-- on log-wrapped output (from nested functions)
-- by writing Unit/Return() and Bind() for the Writer monad in AppleScript

on run {}
    
    -- Derive logging versions of three simple functions, pairing
    -- each function with a particular comment string
    
    -- (a -> b) -> (a -> (b, String))
    set wRoot to writerVersion(root, "obtained square root")
    set wSucc to writerVersion(succ, "added one")
    set wHalf to writerVersion(half, "divided by two")
    
    loggingHalfOfRootPlusOne(5)

    --> value + log string
end run


-- THREE SIMPLE FUNCTIONS
on root(x)
    x ^ (1 / 2)
end root

on succ(x)
    x + 1
end succ

on half(x)
    x / 2
end half

-- DERIVE A LOGGING VERSION OF A FUNCTION  BY COMBINING IT WITH A 
-- LOG STRING FOR THAT FUNCTION
-- (SEE 'on run()' handler at top of script)
-- (a -> b) -> String -> (a -> (b, String))
on writerVersion(f, strComment)
    script
        on call(x)
            {value:sReturn(f)'s call(x), comment:strComment}
        end call
    end script
end writerVersion


-- DEFINE A COMPOSITION OF THE SAFE VERSIONS
on loggingHalfOfRootPlusOne(x)
    logCompose([my wHalf, my wSucc, my wRoot], x)
end loggingHalfOfRootPlusOne


-- Monadic UNIT/RETURN and BIND functions for the writer monad
on writerUnit(a)
    try
        set strValue to ": " & a as string
    on error
        set strValue to ""
    end try
    {value:a, comment:"Initial value" & strValue}
end writerUnit

on writerBind(recWriter, wf)
    set recB to wf's call(value of recWriter)
    set v to value of recB
    
    try
        set strV to " -> " & (v as string)
    on error
        set strV to ""
    end try
    
    {value:v, comment:(comment of recWriter) & linefeed & (comment of recB) & strV}
end writerBind

-- THE TWO HIGHER ORDER FUNCTIONS ABOVE ENABLE COMPOSITION OF 
-- THE LOGGING VERSIONS OF EACH FUNCTION
on logCompose(lstFunctions, varValue)
    reduceRight(lstFunctions, writerBind, writerUnit(varValue))
end logCompose

-- xs: list, f: function, a: initial accumulator value
-- the arguments available to the function f(a, x, i, l) are
-- v: current accumulator value
-- x: current item in list
-- i: [ 1-based index in list ] optional
-- l: [ a reference to the list itself ] optional
on reduceRight(xs, f, a)
    set sf to sReturn(f)
    
    repeat with i from length of xs to 1 by -1
        set a to sf's call(a, item i of xs, i, xs)
    end repeat
end reduceRight

-- Unit/Return and bind for composing handlers in script wrappers
-- lift 2nd class function into 1st class wrapper 
-- handler function --> first class script object
on sReturn(f)
    script
        property call : f
    end script
end sReturn

-- return a new script in which function g is composed
-- with the f (call()) of the Mf script
-- Mf -> (f -> Mg) -> Mg
on sBind(mf, g)
    script
        on call(x)
            sReturn(g)'s call(mf's call(x))
        end call
    end script
end sBind
{
    value:1.61803398875,
    comment:"Initial value: 5\n
             obtained square root -> 2.2360679775\n
             added one -> 3.2360679775\n
             divided by two -> 1.61803398875"
}

EchoLisp

Our monadic Writer elements will be pairs (string . value), where string is the log string.


(define (Writer.unit x (log #f)) 
	(if log (cons log x)
		(cons (format "init → %d" x) x)))

;; f is a lisp function
;; (Writer.lift f) returns a  Writer function which returns a Writer element

(define (Writer.lift f name)     
	(lambda(elem) 
             (Writer.unit 
             	(f (rest elem)) 
                (format "%a \n %a  → %a" (first elem) name (f (rest elem))))))
                            
;; lifts and applies
(define (Writer.bind f elem) ((Writer.lift f (string f)) elem))

(define (Writer.print elem) (writeln 'result (rest elem)) (writeln (first elem)))
		
;; Writer monad versions
(define w-root  (Writer.lift sqrt "root"))
(define w-half  (Writer.lift (lambda(x) (// x 2)) "half"))
(define w-inc  ( Writer.lift add1 "add-one"))


;; no binding required, as we use Writer lifted functions
(->  5 Writer.unit w-root w-inc w-half Writer.print)

result 1.618033988749895    
init → 5
root → 2.23606797749979
add-one → 3.23606797749979
half → 1.618033988749895    

;; binding
(->>  0 Writer.unit (Writer.bind sin) (Writer.bind cos)  w-inc w-half Writer.print)

result 1    
init → 0
sin → 0
cos → 1
add-one → 2
half → 1    

Factor

Factor comes with an implementation of Haskell-style monads in the monads vocabulary.

USING: kernel math math.functions monads prettyprint ;
FROM: monads => do ;

{
    [ 5 "Started with five, " <writer> ]
    [ sqrt "took square root, " <writer> ]
    [ 1 + "added one, " <writer> ]
    [ 2 / "divided by two." <writer> ]
} do .

T{ writer
    { value 1.618033988749895 }
    { log
        "Started with five, took square root, added one, divided by two."
    }
}

Go

package main

import (
    "fmt"
    "math"
)

type mwriter struct {
    value float64
    log   string
}

func (m mwriter) bind(f func(v float64) mwriter) mwriter {
    n := f(m.value)
    n.log = m.log + n.log
    return n
}

func unit(v float64, s string) mwriter {
    return mwriter{v, fmt.Sprintf("  %-17s: %g\n", s, v)}
}

func root(v float64) mwriter {
    return unit(math.Sqrt(v), "Took square root")
}

func addOne(v float64) mwriter {
    return unit(v+1, "Added one")
}

func half(v float64) mwriter {
    return unit(v/2, "Divided by two")
}

func main() {
    mw1 := unit(5, "Initial value")
    mw2 := mw1.bind(root).bind(addOne).bind(half)
    fmt.Println("The Golden Ratio is", mw2.value)
    fmt.Println("\nThis was derived as follows:-")
    fmt.Println(mw2.log)
}

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

Haskell

Haskell has the built-in Monad type class, and a built-in Writer monad (as well as the more general WriterT monad transformer that can make a writer monad with an underlying computation that is also a monad) already conforms to the Monad type class.

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):

import Control.Monad.Trans.Writer
import Control.Monad ((>=>))

loggingVersion :: (a -> b) -> c -> a -> Writer c b
loggingVersion f log x = writer (f x, log)

logRoot = loggingVersion sqrt "obtained square root, "
logAddOne = loggingVersion (+1) "added 1, "
logHalf = loggingVersion (/2) "divided by 2, "

halfOfAddOneOfRoot = logRoot >=> logAddOne >=> logHalf

main = print $ runWriter (halfOfAddOneOfRoot 5)

(1.618033988749895,"obtained square root, added 1, divided by 2, ")

J

Based on javascript implementation:

root=: %:
incr=: >:
half=: -:

tostr=: ,@":

loggingVersion=: conjunction define
  n;~u
)

Lroot=: root loggingVersion 'obtained square root'
Lincr=: incr loggingVersion 'added 1'
Lhalf=: half loggingVersion 'divided by 2'

loggingUnit=: verb define
  y;'Initial value: ',tostr y
)

loggingBind=: adverb define
  r=. u 0{::y
  v=. 0{:: r
  v;(1{::y),LF,(1{::r),' -> ',tostr v 
)

loggingCompose=: dyad define
  ;(dyad def '<x`:6 loggingBind;y')/x,<loggingUnit y
)

Task example:

   0{::Lhalf`Lincr`Lroot loggingCompose 5
1.61803
   1{::Lhalf`Lincr`Lroot loggingCompose 5
Initial value: 5
obtained square root -> 2.23607
added 1 -> 3.23607
divided by 2 -> 1.61803

JavaScript

ES5

(function () {
    'use strict';

    // START WITH THREE SIMPLE FUNCTIONS

    // Square root of a number more than 0
    function root(x) {
        return Math.sqrt(x);
    }

    // Add 1
    function addOne(x) {
        return x + 1;
    }

    // Divide by 2
    function half(x) {
        return x / 2;
    }


    // DERIVE LOGGING VERSIONS OF EACH FUNCTION

    function loggingVersion(f, strLog) {
        return function (v) {
            return {
                value: f(v),
                log: strLog
            };
        }
    }

    var log_root = loggingVersion(root, "obtained square root"),

        log_addOne = loggingVersion(addOne, "added 1"),

        log_half = loggingVersion(half, "divided by 2");


    // UNIT/RETURN and BIND for the the WRITER MONAD

    // The Unit / Return function for the Writer monad:
    // 'Lifts' a raw value into the wrapped form
    // a -> Writer a
    function writerUnit(a) {
        return {
            value: a,
            log: "Initial value: " + JSON.stringify(a)
        };
    }

    // The Bind function for the Writer monad:
    // applies a logging version of a function
    // to the contents of a wrapped value
    // and return a wrapped result (with extended log)

    // Writer a -> (a -> Writer b) -> Writer b
    function writerBind(w, f) {
        var writerB = f(w.value),
            v = writerB.value;

        return {
            value: v,
            log: w.log + '\n' + writerB.log + ' -> ' + JSON.stringify(v)
        };
    }

    // USING UNIT AND BIND TO COMPOSE LOGGING FUNCTIONS

    // We can compose a chain of Writer functions (of any length) with a simple foldr/reduceRight
    // which starts by 'lifting' the initial value into a Writer wrapping,
    // and then nests function applications (working from right to left)
    function logCompose(lstFunctions, value) {
        return lstFunctions.reduceRight(
            writerBind,
            writerUnit(value)
        );
    }

    var half_of_addOne_of_root = function (v) {
        return logCompose(
            [log_half, log_addOne, log_root], v
        );
    };

    return half_of_addOne_of_root(5);
})();
{
    "value":1.618033988749895,
    "log":"Initial value: 5\n
           obtained square root -> 2.23606797749979\n
           added 1 -> 3.23606797749979\n
           divided by 2 -> 1.618033988749895"
}

Jsish

From Javascript ES5 entry.

'use strict';

/* writer monad, in Jsish */
function writerMonad() {
 
    // START WITH THREE SIMPLE FUNCTIONS
 
    // Square root of a number more than 0
    function root(x) {
        return Math.sqrt(x);
    }
 
    // Add 1
    function addOne(x) {
        return x + 1;
    }
 
    // Divide by 2
    function half(x) {
        return x / 2;
    }
 
 
    // DERIVE LOGGING VERSIONS OF EACH FUNCTION
 
    function loggingVersion(f, strLog) {
        return function (v) {
            return {
                value: f(v),
                log: strLog
            };
        };
    }
 
    var log_root = loggingVersion(root, "obtained square root"),
 
        log_addOne = loggingVersion(addOne, "added 1"),
 
        log_half = loggingVersion(half, "divided by 2");
 
 
    // UNIT/RETURN and BIND for the the WRITER MONAD
 
    // The Unit / Return function for the Writer monad:
    // 'Lifts' a raw value into the wrapped form
    // a -> Writer a
    function writerUnit(a) {
        return {
            value: a,
            log: "Initial value: " + JSON.stringify(a)
        };
    }
 
    // The Bind function for the Writer monad:
    // applies a logging version of a function
    // to the contents of a wrapped value
    // and return a wrapped result (with extended log)
 
    // Writer a -> (a -> Writer b) -> Writer b
    function writerBind(w, f) {
        var writerB = f(w.value),
            v = writerB.value;
 
        return {
            value: v,
            log: w.log + '\n' + writerB.log + ' -> ' + JSON.stringify(v)
        };
    }
 
    // USING UNIT AND BIND TO COMPOSE LOGGING FUNCTIONS
 
    // We can compose a chain of Writer functions (of any length) with a simple foldr/reduceRight
    // which starts by 'lifting' the initial value into a Writer wrapping,
    // and then nests function applications (working from right to left)
    function logCompose(lstFunctions, value) {
        return lstFunctions.reduceRight(
            writerBind,
            writerUnit(value)
        );
    }

    var half_of_addOne_of_root = function (v) {
        return logCompose(
            [log_half, log_addOne, log_root], v
        );
    };

    return half_of_addOne_of_root(5);
}

var writer = writerMonad();
;writer.value;
;writer.log;

/*
=!EXPECTSTART!=
writer.value ==> 1.61803398874989
writer.log ==> Initial value: 5
obtained square root -> 2.23606797749979
added 1 -> 3.23606797749979
divided by 2 -> 1.61803398874989
=!EXPECTEND!=
*/
prompt$ jsish -u writerMonad.jsi
[PASS] writerMonad.jsi

Julia

struct Writer x::Real; msg::String; end

Base.show(io::IO, w::Writer) = print(io, w.msg, ": ", w.x)

unit(x, logmsg) = Writer(x, logmsg)

bind(f, fmsg, w) = unit(f(w.x), w.msg * ", " * fmsg)

f1(x) = 7x
f2(x) = x + 8

a = unit(3, "after intialization")
b = bind(f1, "after times 7 ", a)
c = bind(f2, "after plus 8", b)

println("$a => $b => $c")
println(bind(f2, "after plus 8", bind(f1, "after times 7", unit(3, "after intialization"))))


after intialization: 3 => after intialization, after times 7: 21 => after intialization, after times 7, after plus 8: 29
after intialization, after times 7, after plus 8: 29

Kotlin

// version 1.2.10

import kotlin.math.sqrt

class Writer<T : Any> private constructor(val value: T, s: String) {
    var log = "  ${s.padEnd(17)}: $value\n"
        private set

    fun bind(f: (T) -> Writer<T>): Writer<T> {
        val new = f(this.value)
        new.log = this.log + new.log
        return new
    }

    companion object {
        fun <T : Any> unit(t: T, s: String) = Writer<T>(t, s)
    }
}

fun root(d: Double) = Writer.unit(sqrt(d), "Took square root")

fun addOne(d: Double) = Writer.unit(d + 1.0, "Added one")

fun half(d: Double) = Writer.unit(d / 2.0, "Divided by two")

fun main(args: Array<String>) {
    val iv = Writer.unit(5.0, "Initial value")
    val fv = iv.bind(::root).bind(::addOne).bind(::half)
    println("The Golden Ratio is ${fv.value}")
    println("\nThis was derived as follows:-\n${fv.log}")
}

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

zkl

class Writer{
   fcn init(x){ var X=x, logText=Data(Void,"  init \U2192; ",x.toString()) }
   fcn unit(text)  { logText.append(text); self }
   fcn lift(f,name){ unit("\n  %s \U2192; %s".fmt(name,X=f(X))) }
   fcn bind(f,name){ lift.fp(f,name) }
   fcn toString{ "Result = %s\n%s".fmt(X,logText.text) }

   fcn root{ lift(fcn(x){ x.sqrt() },"root") }
   fcn half{ lift('/(2),"half") }
   fcn inc { lift('+(1),"inc") }
}
Writer(5.0).root().inc().half().println();

Result = 1.61803
  init → 5
  root → 2.23607
  inc → 3.23607
  half → 1.61803

w:=Writer(5.0);
Utils.Helpers.fcomp(w.half,w.inc,w.root)(w).println();  // half(inc(root(w)))

Result = 1.61803
  init → 5
  root → 2.23607
  inc → 3.23607
  half → 1.61803

Use bind to add functions to an existing Writer:

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();

Result = 1.61803
  init → 5
  root → 2.23607
  + 1 → 3.23607
  / 2 → 1.61803