Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>It has been a year since I posted this question. After posting it, I delved into Haskell for a couple of months. I enjoyed it tremendously, but I placed it aside just as I was ready to delve into Monads. I went back to work and focused on the technologies my project required.</p> <p>And last night, I came and re-read these responses. <em>Most importantly</em>, I re-read <a href="http://channel9.msdn.com/Shows/Going+Deep/Brian-Beckman-Dont-fear-the-Monads#c633313640460000000" rel="nofollow noreferrer">the specific C# example</a> in the text comments of <a href="http://channel9.msdn.com/shows/Going%2BDeep/Brian-Beckman-Dont-fear-the-Monads/" rel="nofollow noreferrer">the Brian Beckman video</a> someone <a href="https://stackoverflow.com/a/674876/578288">mentions above</a>. It was so completely clear and illuminating that I’ve decided to post it directly here.</p> <p>Because of this comment, not only do I feel like I understand <em>exactly</em> what Monads are … I realize I’ve actually written some things in C# that <em>are</em> Monads … or at least very close, and striving to solve the same problems.</p> <p><strong>So, here’s the comment – this is all a direct quote from <a href="http://channel9.msdn.com/Shows/Going+Deep/Brian-Beckman-Dont-fear-the-Monads#c633313640460000000" rel="nofollow noreferrer">the comment here</a> by <a href="http://channel9.msdn.com/Niners/sylvan" rel="nofollow noreferrer">sylvan</a>:</strong></p> <p>This is pretty cool. It's a bit abstract though. I can imagine people who don't know what monads are already get confused due to the lack of real examples.</p> <p>So let me try to comply, and just to be really clear I'll do an example in C#, even though it will look ugly. I'll add the equivalent Haskell at the end and show you the cool Haskell syntactic sugar which is where, IMO, monads really start getting useful.</p> <p>Okay, so one of the easiest Monads is called the "Maybe monad" in Haskell. In C# the Maybe type is called <code>Nullable&lt;T&gt;</code>. It's basically a tiny class that just encapsulates the concept of a value that is either valid and has a value, or is "null" and has no value.</p> <p>A useful thing to stick inside a monad for combining values of this type is the notion of failure. I.e. we want to be able to look at multiple nullable values and return <code>null</code> as soon as any one of them is null. This could be useful if you, for example, look up lots of keys in a dictionary or something, and at the end you want to process all of the results and combine them somehow, but if any of the keys are not in the dictionary, you want to return <code>null</code> for the whole thing. It would be tedious to manually have to check each lookup for <code>null</code> and return, so we can hide this checking inside the bind operator (which is sort of the point of monads, we hide book-keeping in the bind operator which makes the code easier to use since we can forget about the details).</p> <p>Here's the program that motivates the whole thing (I'll define the <code>Bind</code> later, this is just to show you why it's nice).</p> <pre><code> class Program { static Nullable&lt;int&gt; f(){ return 4; } static Nullable&lt;int&gt; g(){ return 7; } static Nullable&lt;int&gt; h(){ return 9; } static void Main(string[] args) { Nullable&lt;int&gt; z = f().Bind( fval =&gt; g().Bind( gval =&gt; h().Bind( hval =&gt; new Nullable&lt;int&gt;( fval + gval + hval )))); Console.WriteLine( "z = {0}", z.HasValue ? z.Value.ToString() : "null" ); Console.WriteLine("Press any key to continue..."); Console.ReadKey(); } } </code></pre> <p>Now, ignore for a moment that there already is support for doing this for <code>Nullable</code> in C# (you can add nullable ints together and you get null if either is null). Let's pretend that there is no such feature, and it's just a user-defined class with no special magic. The point is that we can use the <code>Bind</code> function to bind a variable to the contents of our <code>Nullable</code> value and then pretend that there's nothing strange going on, and use them like normal ints and just add them together. We wrap the result in a nullable at the end, and that nullable will either be null (if any of <code>f</code>, <code>g</code> or <code>h</code> returns null) or it will be the result of summing <code>f</code>, <code>g</code>, and <code>h</code> together. (this is analogous of how we can bind a row in a database to a variable in LINQ, and do stuff with it, safe in the knowledge that the <code>Bind</code> operator will make sure that the variable will only ever be passed valid row values).</p> <p>You can play with this and change any of <code>f</code>, <code>g</code>, and <code>h</code> to return null and you will see that the whole thing will return null.</p> <p>So clearly the bind operator has to do this checking for us, and bail out returning null if it encounters a null value, and otherwise pass along the value inside the <code>Nullable</code> structure into the lambda.</p> <p>Here's the <code>Bind</code> operator:</p> <pre><code>public static Nullable&lt;B&gt; Bind&lt;A,B&gt;( this Nullable&lt;A&gt; a, Func&lt;A,Nullable&lt;B&gt;&gt; f ) where B : struct where A : struct { return a.HasValue ? f(a.Value) : null; } </code></pre> <p>The types here are just like in the video. It takes an <code>M a</code> (<code>Nullable&lt;A&gt;</code> in C# syntax for this case), and a function from <code>a</code> to <code>M b</code> (<code>Func&lt;A, Nullable&lt;B&gt;&gt;</code> in C# syntax), and it returns an <code>M b</code> (<code>Nullable&lt;B&gt;</code>).</p> <p>The code simply checks if the nullable contains a value and if so extracts it and passes it onto the function, else it just returns null. This means that the <code>Bind</code> operator will handle all the null-checking logic for us. If and only if the value that we call <code>Bind</code> on is non-null then that value will be "passed along" to the lambda function, else we bail out early and the whole expression is null. This allows the code that we write using the monad to be entirely free of this null-checking behaviour, we just use <code>Bind</code> and get a variable bound to the value inside the monadic value (<code>fval</code>, <code>gval</code> and <code>hval</code> in the example code) and we can use them safe in the knowledge that <code>Bind</code> will take care of checking them for null before passing them along.</p> <p>There are other examples of things you can do with a monad. For example you can make the <code>Bind</code> operator take care of an input stream of characters, and use it to write parser combinators. Each parser combinator can then be completely oblivious to things like back-tracking, parser failures etc., and just combine smaller parsers together as if things would never go wrong, safe in the knowledge that a clever implementation of <code>Bind</code> sorts out all the logic behind the difficult bits. Then later on maybe someone adds logging to the monad, but the code using the monad doesn't change, because all the magic happens in the definition of the <code>Bind</code> operator, the rest of the code is unchanged.</p> <p>Finally, here's the implementation of the same code in Haskell (<code>--</code> begins a comment line).</p> <pre class="lang-hs prettyprint-override"><code>-- Here's the data type, it's either nothing, or "Just" a value -- this is in the standard library data Maybe a = Nothing | Just a -- The bind operator for Nothing Nothing &gt;&gt;= f = Nothing -- The bind operator for Just x Just x &gt;&gt;= f = f x -- the "unit", called "return" return = Just -- The sample code using the lambda syntax -- that Brian showed z = f &gt;&gt;= ( \fval -&gt; g &gt;&gt;= ( \gval -&gt; h &gt;&gt;= ( \hval -&gt; return (fval+gval+hval ) ) ) ) -- The following is exactly the same as the three lines above z2 = do fval &lt;- f gval &lt;- g hval &lt;- h return (fval+gval+hval) </code></pre> <p>As you can see the nice <code>do</code> notation at the end makes it look like straight imperative code. And indeed this is by design. Monads can be used to encapsulate all the useful stuff in imperative programming (mutable state, IO etc.) and used using this nice imperative-like syntax, but behind the curtains, it's all just monads and a clever implementation of the bind operator! The cool thing is that you can implement your own monads by implementing <code>&gt;&gt;=</code> and <code>return</code>. And if you do so those monads will also be able to use the <code>do</code> notation, which means you can basically write your own little languages by just defining two functions!</p>
    singulars
    1. This table or related slice is empty.
    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. 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