News for hackers. Stuff that matters.
Re:Functors, applicatives, and monads in pictures by balloot on Sunday May 19, 2013 @12:32AM (#5731799)
Yikes. That might as well be titled "Why functional languages will never catch on." It took something dead simple (a function that adds 3), and made it insanely complicated. Why would anyone choose to deal with that?
Re:Functors, applicatives, and monads in pictures by chousuke on Sunday May 19, 2013 @05:32AM (#5732374)
The function is not the focus. The article presents three abstractions that allow you to apply regular functions on things to which they are not directly applicable.

Maybe is usually used as an example since it's the simplest non-trivial monad (and therefore also an applicative functor).

The point of eg. fmap etc. is that you can have regular Int -> Bool functions, and apply them to data with more structure than simple values. a Maybe String is not a String, but you can still transform one to uppercase by doing fmap (map toUpper) mstring. The fun part is that that exact same thing works on a list of strings, an IO String (fmap (map toUpper) getLine), a Tree of Strings, etc... It's fully generic over anything that can implement Functor; the exact behaviour is defined by the particular instance.

Applicative is just an extension to the idea, where the function applied itself can have this extra structure, and when combined with an infix fmap you get to do

  (+) <$> Just 2 <*> Nothing <*> Just 5  -- Nothing
  (++) <$> getLine <*> getLine -- IO action that reads two lines and concats them
To see why this works has to do with currying. Just stare at the types of fmap and <* > long enough and you should see it eventually.

a Monad is yet more powerful because it allows a previous computation to affect what follows in an arbitrary manner (Applicative doesn't), allowing things like state, asynchronous execution, continuations, and countless other things. It's such an useful abstraction that Haskell provides the do syntax for using it.

Edit: In languages like Java where all types are nullable, if you uppercase a String, but that String is null, your program breaks, even though the type system claims that you have a String when in reality all types are Maybes, and you are forced to always check for nulls manually or just rely on users to not give you nulls, even though it would be trivial for the compiler to check something like that statically if the language were expressive enough to allow it.

Re:Functors, applicatives, and monads in pictures by ams6110 on Sunday May 19, 2013 @11:10AM (#5733041)
So if I understand correctly, the Maybe monad is analogous to SQL's handling of NULL. In SQL, I can invoke the UPPER function on a string, and if that string is a string I get the uppercase version, if it's a NULL I get a NULL in return. I get that, but every time I read about Monads (to the GP's point) it just seems like a very formal academic theory and I keep thinking "so what?" I have not done much with Haskell, maybe it's one of those concepts that seems more natural in practice than it does to try to read about it?
Re:Functors, applicatives, and monads in pictures by steveklabnik on Sunday May 19, 2013 @12:01PM (#5733231)
The big difference is that it's statically computed.

Rust also has a Maybe type as well. You use it like this:

  use core::io::{Reader,ReaderUtil};
  use core::io::println;

  fn main() {
      let in = io::stdin().read_line();
      println("INPUT:");
      println(int::str(int::from_str(in)));
  }
This code will produce an error, because `int::from_str` can fail. Imagine trying to convert a number from the string "foobar".

  $ make
  rustc option.rs
  option.rs.rs:125:23: 125:41 error: mismatched types: expected `int` but found 
  `core::option::Option<int>` (expected int but found enum core::option::Option)
  option.rs:125   io::println(int::str(int::from_str(in)));
                                         ^~~~~~~~~~~~~~~~~~
  error: aborting due to previous error
  make: *** [build] Error 101
What Rust is saying here is that we don't have the right types: `int::str` takes an int, but `int::from_str` returns an `Option<int>`.

We can make the compiler satisfied by pattern matching over the return value:

  use core::io::{Reader,ReaderUtil};
  use core::io::println;

  fn main() {
      let in = io::stdin().read_line();

      match int::from_str(in) {
          Some(number_string) => println(int::to_str(number_string)),
          None                => println("Hey, put in a number.")
      }
  }
Now, we explicitly handle both cases (Some(x) being a success, and None being the failure), and the compiler is happy.

This is where the advantages of Maybe come into play. In dynamic languages, you don't get the advantage of always making sure you handle the degenerate case.

Now, what the Maybe _monad_ does is allow you to chain multiple things that work with Maybe together. I don't have a Rust example of this handy. Like "Do this, do that, do the other thing, and then let's see if that failed anywhere along the way."

Re:Functors, applicatives, and monads in pictures by chousuke on Sunday May 19, 2013 @12:42PM (#5733404)
The reason why people talk so much about monads is that they are ubiquitous, and Haskell in particular can make good use of them because if type classes and other high level abstraction facilities, plus do notation.

Asynchronous execution is one particular case that I like as an example: You can implement promises (which represent async computations) in Haskell and such a Promise type will also be able to implement the monad type class. Because they are monads, you can use do notation:

  -- Let's assume we want to fetch two large datasets asynchronously over the network and filter them

  asyncSanitize :: Promise [String] -> Promise [String] -> Promise [String]
  asyncSanitize p1 p2 = do 
    x <- p1
    y <- p2
    return (sanitize (x ++ y)) -- no callbacks!
which looks like the same code you would use for filtering two Maybe values using do notation. In fact, it is the same code, and if you leave out the type signature, then "asyncSanitize" will work for any monadic value: you could easily test your function using eg. Identity [String] (pure values), IO String (synchronous fetching), or decide to switch to some Database monad instead that fetches the values on demand from the Database. The code will not need to change at all.
Re:Functors, applicatives, and monads in pictures by lobster_johnson on Sunday May 19, 2013 @05:20PM (#5734432)
Sort of like NULL, especially in that both NULL and Nothing mean "the absence of a value" and cannot be combined or compared with anything else. But it goes way beyond that.

Think of Maybe as a container. It either "contains" a value, or it doesn't. The container itself is not usable except for passing around; it's the contained value that is important. Even if we know that the container is supposed to contain a number, we can't use the container to perform computations; every time we need the number, we need to open the container, peek inside, and decide what to do whether it's contains something or nothing.

In Haskell terms, this "peeking inside" is typically done with pattern matching, which is core to the type system. For example, this is a function that checks if a Maybe value has anything, and returns true or false:

    hasValue x =
      case x of
        Just _ -> True
        Nothing -> False
The line "Just _" is a kind of wildcard expression, meaning: "Check if x matches the pattern Just [something]".

At the opposite end, we can have functions that produce Maybes (naive and simplified example, not working code):

    fetchPage url =
      do response <- performHttpRequest "GET" url
         case (getStatusCode response)
           200 -> return (Just (getBody response))
           404 -> return Nothing
Notice how "Just" looks like a function call. That's because it is. It's a function that "constructs" a value of, in this case, type "Maybe String". The "Nothing" returned is also a value of type "Maybe String". Thanks to Haskell's type inference, this is known at compile time.

In languages such as Java or Ruby we can build classes that are containers that act in a similar way. But those languages are limited in that "peek inside the container" logic needs to happen at runtime. In Haskell, the container's possible values are enforced entirely by the type system at compile time.

To really appreciate this, you really have to be familiar with statically typed languages such as C++ or Java. In such languages, you have "nil" or "null" or "NULL" values to represent "nothing". Any time you have a pointer, you have to explicitly check if the pointer is valid; if you try to use it, and it happens to be null, the program will blow up at runtime, but not at compile time.

In Haskell, there is no generic null value. The value "Nothing" on its own belongs to a specific type, such as "Maybe String", and won't work with another such as "Maybe Integer". Thus when we want to use "fetchPage", we are forced into a situation where must make a choice based on whether there is a value or not (again, naive example):

    crawlPageRecursively url =
      do contents <- fetchPage url
         case contents of
           Just s -> map crawlPageRecursively (map (\body -> getLinks body) s)
           Nothing -> putStrLn ("Failed to fetch " ++ url)
Since Haskell doesn't have null pointers, and can never end up in a situation where you try to use a null where you expected a value, because its type system makes it impossible.

This was my attempt at "explain it like I'm five" Haskell as carefully as I could. The real world is somewhat more complex, but not awfully so. As you say, too often haskellers will get into "formal academic theory", even when, in my opinion, it's not necessary. Haskell becomes more elegant and beautiful if you study and know group theory, but most people don't, and it really just obscures the language for ordinary, mortal programmers who are trying to learn it.

As for monads, it's true that Maybe is a monad, but think of it as a convenience, in the sense that this lets it play well with the rest of the monad infrastructure. You can use, and even implement, Maybe without involving the monad aspect.

My best suggestion regarding monads is to just start using the language; as DanWaterworth points out, monads are pretty much inexplicable for beginners until one really needs to use them. Haskell actually lets you use some monads (like IO) without requiring any deep understanding of what they are. Case in point: The above examples actually use the IO monad, concealed by the "do" and the "<-" syntax. But because this syntactic sugar makes the language look like an imperative language, you can use this stuff without too much deep knowledge about just exactly how it works under the hood.

Re:Functors, applicatives, and monads in pictures by seldo on Sunday May 19, 2013 @12:43AM (#5731826)
They chose a deliberately over-simplified example in order to demonstrate the core concepts; I don't begrudge them that (nobody needs a program that prints out "Hello World!").

The audience level of this piece is confusing -- it looks like a friendly, cartoony introduction for a general audience, but it actually assumes you already know Haskell.

Basically, you and I are not the intended audience.

Re:Functors, applicatives, and monads in pictures by balloot on Sunday May 19, 2013 @12:59AM (#5731871)
I know a bit about Haskell and have played with it. I guess it just seems like functional languages are for those who want to solve super complicated mental exercises when doing tasks that would otherwise be easy using a traditional language.

There are very few things in the world of CS/programming where I can't follow along and grok what's going on, especially when laid out in a tutorial form like this. The fact that I was totally lost when reading this is not a good sign when you're trying to get people to adopt your school of thought.

Re:Functors, applicatives, and monads in pictures by ww520 on Sunday May 19, 2013 @03:12AM (#5732131)
To the other people saying that pure functional programming is the reason that it's difficult to explain Haskell to other programmers and blaming them for doing too much imperative style coding, it's the wrong assumption. Pure functional programming has nothing to do with the difficulty in explaining Haskell. Pure functional programming is in Lisp/Schema/C#/Clojure/and other languages and people have no trouble learning it.

Haskell is difficult to explain because it has many terms, vocabulary, and syntax that are not familiar to people. It's ML-style syntax doesn't help.

Most tutorials targeting Haskell beginners implicitly assume the readers already know the Haskell syntax, terms, definition, etc, and go right ahead to explain the advance concepts like functor, applicative, or monad. It's like teaching them how to fly before they know how to walk, in the Haskell land. No wonder Haskell beginners are frustrated with any of the monad tutorial.

The thing is. Stop. Stop telling beginners what monad is. Just show them the basics in Haskell and get something useful going. Get them to write and use Haskell programs. When the need arise, they will look into what monad is. Programmers have used STL plenty without knowing the internals of C++ templates. Same thing can be done with monad.

Re:Functors, applicatives, and monads in pictures by egonschiele on Monday May 20, 2013 @01:00AM (#5735992)
Just to follow up on your other comment:

> When the need arise, they will look into what monad is.

I couldn't have said it any better. This is the exact scenario that this post is aimed at.

Re:Functors, applicatives, and monads in pictures by chongli on Sunday May 19, 2013 @02:20AM (#5732035)
>There are very few things in the world of CS/programming where I can't follow along and grok what's going on, especially when laid out in a tutorial form like this.

That's probably because most of the tutorials you've followed have adopted an imperative style of programming. It is easy for you to follow along because it really isn't all that different from what you are accustomed to. Functional programming really is a different beast entirely. It's often said (though I remain skeptical) that it's actually easier to learn functional programming as a non-programmer than to un-learn your imperative programming tendencies.

>The fact that I was totally lost when reading this is not a good sign when you're trying to get people to adopt your school of thought.

I don't think that's a fair assessment. You could say the same thing about starting from functional programming and switching to imperative; some people actually do this! They find the idea of mutating a variable to be completely counter-intuitive!

Re:Functors, applicatives, and monads in pictures by balloot on Sunday May 19, 2013 @04:01AM (#5732217)
I would love to meet this mythical being who understands functional programming but has no clue how to write an imperative program.
Re:Functors, applicatives, and monads in pictures by wwweston on Sunday May 19, 2013 @04:53AM (#5732302)
While going through a Math undergrad program in the mid-90s, I noticed that some number of my fellow students had a distaste for programming.

As someone who'd done reasonably well with both and had thought of them as heavily overlapping areas, I thought this was interesting, so I tried to poke at this a bit.

One of the concepts I got back from a talented classmate was basically a complaint about mutable variables -- that in an algebraic description of relationships for a given system what we call "variables" are less variable and more "unknowns" which represent fixed if unidentified quantities. Others similarly noted there was something absurd about writing out equations like "x = x + 2".

Re:Functors, applicatives, and monads in pictures by tripzilch on Sunday May 19, 2013 @05:27PM (#5734455)
I can see why they think that, but the important thing is that "x = x + 2" is not an equation. It's just an arguably poorly chosen operator (Pascal gets this right and uses ":=" for assignment).

The trick is to stop reading that line (in your head) as "x is equal to x plus two", but instead "x is assigned the value of x plus two".

Re:Functors, applicatives, and monads in pictures by wwweston on Sunday May 19, 2013 @07:56PM (#5734988)
> It's just an arguably poorly chosen operator (Pascal gets this right and uses ":=" for assignment).

That's one potential takeaway, but when I turned over the complaint in my mind, this was arguably another way of complaining about mutability.

Also, given the timing, it's pretty likely that one of the languages they'd learned was Pascal: that was the language of the first few CS classes at my school in the 90s, it was also the language of any high school curriculum that led to the AP exam, and Borland's Pascal products were still pretty popular PC dev environments.

They could've also been unlucky and received their first exposure by choosing to do a numerical analysis class in Fortran or C, of course. :/

Re:Functors, applicatives, and monads in pictures by Shorel on Sunday May 19, 2013 @10:34AM (#5732937)
Most students of pure mathematics get functional programming much faster than imperative programming if they have never programed before.

Source: all my classmates.

Re:Functors, applicatives, and monads in pictures by ParahSailin on Sunday May 19, 2013 @01:01PM (#5733484)
People who exclusively use Excel spreadsheets to program is a good example. Most people who use spreadsheets never use functions in a cell whose effect is to change the function or value in another cell.
Re:Functors, applicatives, and monads in pictures by cynwoody on Sunday May 19, 2013 @03:29AM (#5732163)
> They find the idea of mutating a variable to be completely counter-intuitive!

The notion of mutation is implicit in the definition of "variable."

Re:Functors, applicatives, and monads in pictures by chousuke on Sunday May 19, 2013 @04:39AM (#5732277)
Except it isn't. Unless you learn imperative programming before you learn basic algebra, the first definition of a variable you encounter is that of an immutable one.
Re:Functors, applicatives, and monads in pictures by Shorel on Sunday May 19, 2013 @10:33AM (#5732934)
Actually an algebraic variable is named that way because you can change it every time you do the exercise.

So you don't change it during one exercise, but you can and certainly will change it when you change the exercise to another one with the same principle.

Re:Functors, applicatives, and monads in pictures by tikhonj on Sunday May 19, 2013 @11:32AM (#5733130)
That behaves just like a function: the values of the variables change each time you call the function but not within. When you do a new exercise, it's really a bunch of new variables with the same name--variables cannot affect each other between exercises!

That's not analogous at all to mutation.

Re:Functors, applicatives, and monads in pictures by chongli on Sunday May 19, 2013 @11:17AM (#5733062)
Right, but you're not mutating it in the middle of your calculation.
Re:Functors, applicatives, and monads in pictures by Gravityloss on Sunday May 19, 2013 @01:47PM (#5733687)
If you have a sum for example sum_{x=1}^{10}x^2, x definitely changes quite many times during your calculation.
Re:Functors, applicatives, and monads in pictures by chongli on Sunday May 19, 2013 @03:43PM (#5734136)
No, that's an example of recursion. With recursion you aren't mutating the variable, you're shadowing its definition. This is a subtle, but important, distinction.
Re:Functors, applicatives, and monads in pictures by Gravityloss on Sunday May 19, 2013 @04:51PM (#5734348)
Recursion? The "function" is not calling itself at all. I'm quite sure that is not recursion, neither in the mathematical nor computer science sense.
Re:Functors, applicatives, and monads in pictures by chongli on Sunday May 19, 2013 @05:57PM (#5734570)
Recursion is how you implement a sum without mutation (an imperative loop is how you'd implement it with mutation). You've merely given me the function written in a declarative notation.
Re:Functors, applicatives, and monads in pictures by Gravityloss on Tuesday May 21, 2013 @11:54AM (#5744509)
I think we are talking about different things.

For example, if you integrate x^2 dx from x=0 to 10, x changes continuously.

It's clear that x is not fixed to any particular value.

Re:Functors, applicatives, and monads in pictures by chongli on Wednesday May 29, 2013 @05:32AM (#5785400)
Yeah, you're talking about the mathematical definition of a bound variable. Functional programming languages use this whenever you define a function:

   foo x = x * 2
Every time you call foo, x is bound to a new value (but only within the scope of foo). This is not the same as mutating some memory location associated with the name x.
Re:Functors, applicatives, and monads in pictures by chousuke on Monday May 20, 2013 @01:26PM (#5738792)
x does not mutate at all. x is simply a placeholder for the values in the series of additions that your expression expands to, that is, 1² + 2² + 3² + ... + 10². Or stepwise, to 1² + sum_{x=2}^{10}x² etc. all three expressions are equivalent, and no mutation of x occurs anywhere

The series of additions can also be infinite, in which case it would be quite difficult to expand fully, but that doesn't prevent you from doing mathematics with it.

Re:Functors, applicatives, and monads in pictures by ams6110 on Sunday May 19, 2013 @11:21AM (#5733086)
An algebraic "variable" is perhaps better called an "unknown"
Re:Functors, applicatives, and monads in pictures by tel on Sunday May 19, 2013 @02:19AM (#5732030)
This is a pretty common idea, but it's because pure functional programming is, at first, all about getting you to significantly change your programming POV. It's a shift for anyone---in fact, the better you are at understanding C/Ruby/Python/Perl/Java/ObjC/Lua the harder a shift it is.

At the end of the day, you adopt a new way of thinking that is incredibly clarifying for all programming. One simple thing is that it allows you to "see" where state, re-entry, evaluation, IO, and failure are happening in a program---things that you are blind to when you're used to languages where the answer is "always".

This article isn't even meant to explain why you ought to learn Haskell. It's more like a signpost on your path to mastery, should you begin walking it.

Re:Functors, applicatives, and monads in pictures by egonschiele on Sunday May 19, 2013 @01:14AM (#5731912)
Post author here. I'd love to know where you stumbled!
Re:Functors, applicatives, and monads in pictures by olavk on Sunday May 19, 2013 @12:09PM (#5733263)
In other communities, new tools and abstractions are generally "sold" by explaining how they are useful for solving specific problems. Not so in the Haskell community though.

The Haskell community has a longstanding tradition of using condescending language ("fmap is from the street, fmap is hip to contexts."), and deliberate childrens-book style metaphors and illustrations in tutorials.

The theory seem to be that if monads haven't been adopted by mainstream developers yet, it is just because the presentations haven't been dumbed-down and kiddie-friendly enough yet. (If only they from the onset had called "monads" for "warm fuzzy things" instead, surely developers would not be so scared of them!)

The strategy have not yet borne fruit, though.

Re:Functors, applicatives, and monads in pictures by egonschiele on Sunday May 19, 2013 @12:54AM (#5731854)
Right. I'm hoping to make monads easier to understand, but you need some knowledge of functional programming to build on. If I had tried catering to the complete beginner, this post would be much longer and not as focused :)
Re:Functors, applicatives, and monads in pictures by seldo on Sunday May 19, 2013 @01:00AM (#5731876)
That's fair enough! Perhaps a sentence at the beginning to establish your goal would prevent comments from confused clueless people like myself.
Re:Functors, applicatives, and monads in pictures by egonschiele on Sunday May 19, 2013 @01:10AM (#5731902)
Done!
Re:Functors, applicatives, and monads in pictures by chii on Sunday May 19, 2013 @12:56AM (#5731860)
> They chose a deliberately over-simplified example in order to demonstrate the core concepts;

i wish people who are writing guides on these topics pick a non-simplified situation where using this method makes for an easier program (vs using the "traditional method"). The comparison and contrasting of a functional/monadic approach vs a procedural approach in a complex scenario might actually shed more light - at least, for some one who is familiar with the procedural approach.

Re:Functors, applicatives, and monads in pictures by balloot on Sunday May 19, 2013 @01:03AM (#5731888)
I would love to see this! One of the fundamental issues I have with functional languages is every example I see is basically "See this thing that's relatively simple and uncomplicated in Ruby/PHP/C/whatever? Here's how to do that in Haskell!" And the Haskell version ends up being extremely unintuitive and complicated. Bottom line is I still don't know for which situations functional languages are a "good" tool.
Re:Functors, applicatives, and monads in pictures by gizmo686 on Sunday May 19, 2013 @01:29AM (#5731951)
I think the problem is that the Haskell version is actually very simple, to the person writing it. Its a classical problem of teaching, it is extremly easy to forget how something looks to new people.
Re:Functors, applicatives, and monads in pictures by egonschiele on Monday May 20, 2013 @01:03AM (#5736004)
Again, if you tell me where you're stumbling, I can fix it. I see your complaints all over this post and you haven't responded to me once.
Re:Functors, applicatives, and monads in pictures by nandemo on Sunday May 19, 2013 @10:03AM (#5732863)
That approach is used at length in Real World Haskell. For example, some code for key-value lookup is shown that deals with a series of Maybe foo values, first with a cascade of guards (think a cascade of if-else's), and later with monad syntax. There are other examples.

http://book.realworldhaskell.org/read/programming-with-monad...

Re:Functors, applicatives, and monads in pictures by lobster_johnson on Sunday May 19, 2013 @09:05PM (#5735231)
I enjoyed RWH much more after having learned a lot of the basics. It starts off simple, to be sure, but then quickly jumps into the deep end. For a book that's about real-world stuff it gets into a lot of unnecessary detail, too, that should have been deferred until later "advanced" chapters. I appreciated the hands-on approach to real examples, though.

"Learn You A Haskell For Great Good" [1], while much less complete, is the best intro I have found so far. It's also free.

[1] http://learnyouahaskell.com/

Re:Functors, applicatives, and monads in pictures by dscrd on Sunday May 19, 2013 @09:50AM (#5732837)
"functional languages" is a rather wide concept, but I would accept "Why this particular aspect of functional languages will never catch on". Many other aspects have already been assimilated by pratically everyone.
Re:Functors, applicatives, and monads in pictures by Tycho on Sunday May 19, 2013 @05:51PM (#5734553)
It's sort of like those bizarre outfits you see on catwalks, parts/details of which actually filter through to mainstream clothes eventually.
Re:Functors, applicatives, and monads in pictures by tikhonj on Sunday May 19, 2013 @11:35AM (#5733136)
Have you seen how much complexity Java has just for hello world!? It's truly absurd. And, as somebody who's tried teaching Java to complete beginners, I can attest that it isn't intuitive at all.

There's no way this Java thing will catch on. Why would anyone choose to deal with it?

Re:Functors, applicatives, and monads in pictures by olavk on Sunday May 19, 2013 @11:57AM (#5733220)
Haskell and Java are not the only language in the world. The poster might prefer an OO-language without the HelloWorld-overhead as Java. Like, say, Python where hello world is literally

  print "Hello World"
And in the case of Java, it is well known that Java is not intended or used for writing one-lines, so it is not really a relevant criticism. And even if it were, it doesn't refute any criticism of Haskell that you are able to point out unrelated shortcomings in an unrelated language.
Re:Functors, applicatives, and monads in pictures by tikhonj on Sunday May 19, 2013 @02:50PM (#5733976)
My point was that it hasn't stopped Java from becoming popular--more popular than Python, even! After all, people do choose to deal with all the wanton complexity of Java.

Also, the example of hello world doesn't show much about complexity. After all, in Haskell it's just:

    main = putStr "Hello World"
Re:Functors, applicatives, and monads in pictures by nickknw on Sunday May 19, 2013 @02:32PM (#5733897)
I would say it used a dead simple function as a device to help explain a bunch of other things.