Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p><strong>The precise technical definition</strong>: A monad, in Ruby, would be any class with <code>bind</code> and <code>self.unit</code> methods defined such that for all instances m:</p> <pre><code>m.class.unit[a].bind[f] == f[a] m.bind[m.class.unit] == m m.bind[f].bind[g] == m.bind[lambda {|x| f[x].bind[g]}] </code></pre> <p><strong>Some practical examples</strong></p> <p>A very simple example of a monad is the lazy Identity monad, which emulates lazy semantics in Ruby (a strict language):</p> <pre><code>class Id def initialize(lam) @v = lam end def force @v[] end def self.unit lambda {|x| Id.new(lambda { x })} end def bind x = self lambda {|f| Id.new(lambda { f[x.force] })} end end </code></pre> <p>Using this, you can chain procs together in a lazy manner. For example, in the following, <code>x</code> is a container "containing" <code>40</code>, but the computation is not performed until the second line, evidenced by the fact that the <code>puts</code> statement doesn't output anything until <code>force</code> is called:</p> <pre><code>x = Id.new(lambda {20}).bind[lambda {|x| puts x; Id.unit[x * 2]}] x.force </code></pre> <p>A somewhat similar, less abstract example would be a monad for getting values out of a database. Let's presume that we have a class <code>Query</code> with a <code>run(c)</code> method that takes a database connection <code>c</code>, and a constructor of <code>Query</code> objects that takes, say, an SQL string. So <code>DatabaseValue</code> represents a value that's coming from the database. DatabaseValue is a monad:</p> <pre><code>class DatabaseValue def initialize(lam) @cont = lam end def self.fromQuery(q) DatabaseValue.new(lambda {|c| q.run(c) }) end def run(c) @cont[c] end def self.unit lambda {|x| DatabaseValue.new(lambda {|c| x })} end def bind x = self lambda {|f| DatabaseValue.new(lambda {|c| f[x.run(c)].run(c) })} end end </code></pre> <p>This would let you chain database calls through a single connection, like so:</p> <pre><code>q = unit["John"].bind[lambda {|n| fromQuery(Query.new("select dep_id from emp where name = #{n}")). bind[lambda {|id| fromQuery(Query.new("select name from dep where id = #{id}"))}]. bind[lambda { |name| unit[doSomethingWithDeptName(name)] }] begin c = openDbConnection someResult = q.run(c) rescue puts "Error #{$!}" ensure c.close end </code></pre> <p>OK, so why on earth would you do that? Because there are extremely useful functions that can be written once <em>for all monads</em>. So code that you would normally write over and over can be reused for any monad once you simply implement <code>unit</code> and <code>bind</code>. For example, we can define a Monad mixin that endows all such classes with some useful methods:</p> <pre><code>module Monad I = lambda {|x| x } # Structure-preserving transform that applies the given function # across the monad environment. def map lambda {|f| bind[lambda {|x| self.class.unit[f[x]] }]} end # Joins a monad environment containing another into one environment. def flatten bind[I] end # Applies a function internally in the monad. def ap lambda {|x| liftM2[I,x] } end # Binds a binary function across two environments. def liftM2 lambda {|f, m| bind[lambda {|x1| m.bind[lambda {|x2| self.class.unit[f[x1,x2]] }] }] } end end </code></pre> <p>And this in turn lets us do even more useful things, like define this function:</p> <pre><code># An internal array iterator [m a] =&gt; m [a] def sequence(m) snoc = lambda {|xs, x| xs + [x]} lambda {|ms| ms.inject(m.unit[[]], &amp;(lambda {|x, xs| x.liftM2[snoc, xs] }))} end </code></pre> <p>The <code>sequence</code> method takes a class that mixes in Monad, and returns a function that takes an array of monadic values and turns it into a monadic value containing an array. They could be <code>Id</code> values (turning an array of Identities into an Identity containing an array), or <code>DatabaseValue</code> objects (turning an array of queries into a query that returns an array), or functions (turning an array of functions into a function that returns an array), or arrays (turning an array of arrays inside-out), or parsers, continuations, state machines, or anything else that could possibly mix in the <code>Monad</code> module (which, as it turns out, is true for almost all data structures).</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload