Monads/Writer monad: Difference between revisions

From Rosetta Code
Content added Content deleted
(J draft)
Line 94: Line 94:


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





Line 131: Line 130:
// and then nests function applications (working from right to left)
// and then nests function applications (working from right to left)
function logCompose(lstFunctions, value) {
function logCompose(lstFunctions, value) {
return lstFunctions
return lstFunctions.reduceRight(
.reduceRight(function (writerA, f) {
writerBind,
return writerBind(writerA, f);
writerUnit(value)
}, writerUnit(value));
);
}
}



Revision as of 10:43, 3 February 2016


The Writer monad is a coding pattern which allows composition of functions which return their results combined with a log string. The final result of a composed function yields both the resulting value, and a concatenation of the logs from each component function application.

Demonstrate in your programming language the following:

  1. 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)
  2. Write three simple functions: root, addOne, and half
  3. Derive Writer monad versions of each of these functions
  4. 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.)


J

Based on javascript implementation:

<lang J>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

)</lang>

Task example:

<lang J> 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</lang>

JavaScript

ES5

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

})();</lang>

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