Monads/Writer monad: Difference between revisions
m (→ES5) |
(J draft) |
||
Line 10: | Line 10: | ||
# 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.) |
# 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.) |
||
=={{header|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> |
|||
=={{header|JavaScript}}== |
=={{header|JavaScript}}== |
Revision as of 09:02, 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:
- 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.)
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(function (writerA, f) { return writerBind(writerA, f); }, 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" }