7 ms·
If we look at an impure language like JavaScript through Haskell-colored glasses, essentially every line of code in a JS program is automatically in the IO mona
by tmhedberg 14y ago
If we look at an impure language like JavaScript through Haskell-colored glasses, essentially every line of code in a JS program is automatically in the IO monad. Haskell's bonus is that it gives you the frequently-exercised option of writing code that's explicitly not capable of doing I/O, simply by omitting IO from its type, and having this constraint enforced by the compiler. This self-imposed restriction helps avoid the numerous problems that come along with uncontrolled side effects. But since you can't "escape" the IO monad in JavaScript, there's not much point in making it explicit by doing output in a visibly monadic way.
That being said, there are plenty of uses for the monad pattern outside of the I/O domain. That's where a lot of emphasis is placed in Haskell, because Haskell couldn't do I/O without monads, but there are tons of other useful monads that have nothing to do with side effects. As the article illustrates, two of these are Writer and List (written as [] in Haskell). Another massively useful one is Maybe, which represents nullability, but by making it explicit in a value's type we can avoid a lot of the problems that arise in "nullable by default" languages.
In some sense, jQuery is an example of a monadic library, wherein the unit function is $, which lifts its argument into the jQuery monad, and bind is represented by the chain of method calls applied to that lifted value, each of which returns a different value, still wrapped in the jQuery monad. I've been told that LINQ in the C# world works similarly (in fact, there is supposedly a lot of bleed-over of ideas from Haskell into .NET because Simon Peyton-Jones works alongside some of the .NET language designers at Microsoft Research).
- jlarocco 14y agoThis is one of the reasons why I don't use Haskell. Every concept you mention is made more complicated thinking about it with monads. Every time I use Haskell I feel like too much mental energy is wasted on silly stuff like this.
- zaptheimpaler 14y agoDisclaimer: I've never used Haskell Yeah, although the article mentions how monads eliminate some boilerplate code, the whole concept of monads is lots of boilerplate code that doesn't exist in other languages. I don't really see the point of writing something like a web server or anything that interfaces a lot with users in Haskell. Seems like its strengths are manipulating data and parallelism, but it would make more sense to use a wrapper around it to handle I/O.
- numeromancer 14y agoMonads are important in providing well-defined semantics for code. They are a way of taking imperative code and making it functional; the semantics of functional computation are much easier to define than those of imperative code. If you were interested in proving your program correct with a deductive proof (rather than, say, statistically acceptable with tests) , monads would be very important to you. They weren't designed to provide useful design patterns. That's why articles attempting to demonstrate them as useful design patterns often seem artificial. But I think that as the art of software engineering progresses, the problems they solve will become more important.
- tmhedberg 14y agoLet's say I have several functions I want to compose, feeding the result of one as the argument to the next. But each of these functions has some failure condition, which, if it occurs, causes the function to be unable to return a normal result. In an imperative language, I might represent that failure by returning a null reference, and I'd write something like this: fooResult = foo(x); if (fooResult == null) { return null; } else { barResult = bar(fooResult); if (barResult == null) { return null; } else { bazResult = baz(barResult); if (bazResult == null) { return null; } else { quuxResult = quux(bazResult); if (quuxResult == null) { return null; } else { return quuxResult; } } } } I think that's a pretty common pattern: call a function and check whether it succeeded. If it did succeed, then pass its result to the next function and repeat. If it failed, then propagate the failure outwards, skipping the rest of the computation. But that's pretty tedious and repetitive code to write. The signal to noise ratio is incredibly low. Not only that, but if I get lazy or forgetful and don't check for null in any one of those cases, my code could blow up at runtime. It would be nice if we could abstract out the pattern of error checking and propagation of errors so we didn't have to type so much boilerplate around the real meat of the computation, which is just the four function calls. Haskell's Maybe type serves precisely this purpose. The exact same code as above, in Haskell using the Maybe monad, would be: return x >>= foo >>= bar >>= baz >>= quux That's it! Error propagation will happen automatically, and if no errors occur along the way, we'll get the same result at the end. Now, you might think that there must be a lot going on behind the scenes to make that one-liner actually do what we want it to do. But there isn't really. Maybe comes for free in the standard libraries, and even if it didn't, we could trivially define it ourselves like this: data Maybe a = Nothing | Just a instance Monad Maybe where return = Just Nothing >>= _ = Nothing Just x >>= f = f x That's the entire definition of the Maybe data type and its complete error propagation behavior. There's nothing more to it than that. And not only will it work in the specific example I gave, but in any situation where I have a chain of functions to call that might fail in some way. After writing that once (or not at all, since it's in the libraries), I can now apply that pattern anywhere I need it, in any program, to concisely express what took around 20 lines of onerous and error-prone repetition without the benefit of the monad. That's how monads eliminate boilerplate, and one of the reasons why you might benefit from understanding them even if you're not a Haskell user.
- bluekeybox 14y ago> In some sense, jQuery is an example of a monadic library, wherein the unit function is $, which lifts its argument into the jQuery monad, and bind is represented by the chain of method calls applied to that lifted value, each of which returns a different value, still wrapped in the jQuery monad. Aha. Thank you. Ever since I first learned about monads in Haskell (which is not so long ago), I kept noticing examples of such patterns in some libraries and was wondering whether it's only me who thinks there is a similarity.
- saraid216 14y agoI've found it easiest to understand monads as "the theoretical basis behind what a lot of languages think of as features". The purpose of understanding monads feels to me as an exercise in returning to first principles. Naturally, this has the usual consequence of first principles: a lot of things that seem obvious are no longer Just There for you to Take For Granted. That said, I'm not really prepared to say I understand monads. :P
- pash 14y ago> ... LINQ in the C# world works similarly (in fact, there is supposedly a lot of bleed-over of ideas from Haskell into .NET because Simon Peyton-Jones works alongside some of the .NET language designers at Microsoft Research). Erik Meijer, the creator of LINQ, is himself a functional-programming guru. A couple of years ago, he gave a series of lectures on Haskell for MSDN's Channel 9 [0] that are a great introduction to Haskell and FP generally. Throughout the series, he points out intriguing connections between the ways of doing things in Haskell and C# that at first seem like they could not be more different. 0. http://channel9.msdn.com/Series/C9-Lectures-Erik-Meijer-Functional-Programming-Fundamentals/Lecture-Series-Erik-Meijer-Functional-Programming-Fundamentals-Chapter-1 http://channel9.msdn.com/Series/C9-Lectures-Erik-Meijer-Func...