FranklinChen / monad-scratchpad

Unfinished stuff involving monads
0 stars 0 forks source link

Notes on the example #1

Open joelmccracken opened 10 years ago

joelmccracken commented 10 years ago

Hey Franklin,

Thanks for putting this together. I can't comment directly on that code (I assume because I don't own the repo), so this will do.

So, in the context of what I was trying to say on twitter, basically, is that much of the discussions around Haskell seem unnecessarily opaque. I don't really know how to explain this, so I am going to frame it as a dialog between a novice and an expert:

Novice: Hey, I have heard about this Haskell language... it seems cool but very foreign. What is it like?

Expert: Well, it is a lazy, strongly typed, pure functional programming language.

N: Hmm. What do you mean by some of those terms? What does lazy mean? What is a pure functional programming language.

E: Well, lazy refers to (insert explanation of lazy here, not impt for discussion)

N: Ok; that sounds really cool, although I am unsure how I would use it. What about "purely functional"?

E: So, in Haskell, side effects such as IO are handled in a very special way. Haskell code is side-effect free.

N: That is interesting. But the language must actually do some IO, otherwise it wouldn't be useful.

E: Right! So in Haskell we use Monads to do IO. Here, this is what a monad looks like:
###
Haskell:
class Monad m where
return :: a -> m a
(>>=) :: m a -> (a -> m b) -> m b
fmap :: (a -> b) -> m a -> m b
fmap f ma = ma >>= \a -> return $ f a
###

... at which point the novice gives up. What does all that have to do with IO? Even if they take the time to understand the function signatures and definitions, these don't have anything to do with IO, which is even more confusing.

A clearer explanation of the whole thing to me would be: A monad is a tool that is used to interface between pure and impure functional code. Function application is used to order statements chronologically, which is necessary because of lazy evaluation Haskell. IO is actually implemented in C.

Of course, what I am saying might be wrong. I do think that the explanation of a monads is very off-putting, though. Because the definitions novices are shown have nothing to do with IO, and no explanation is really made about why we are looking at this thing when it doesn't actually do IO.

Does that all make any sense?

FranklinChen commented 10 years ago

I apologize for just putting up the code, with some comments and examples but no actual explanation. I just wanted to get something out to you quickly as something concrete. It's best to explain this stuff in an interactive dialogue with a chalk board and drawing :-).

The first thing to note is that monads have nothing to do with IO or state or laziness (I gave you CoffeeScript code, after all), but are a very general model of computation of immense practical use in many situations; in fact, I never use an IO monad in my Scala code but use monads all the time. (In fact, the Scalaz library does define an IO monad but I just didn't feel it was useful enough for me to justify squeezing my code into it.)

The use of a monad for IO in Haskell is, frankly, a hack, a trick, and a controversial one, but was done because it was a way to be pragmatic and get things done at a time when Haskell IO was otherwise very problematic: I first learned Haskell in 1994 and remember doing a tiny bit of programming with an older version of Haskell without monads. It was painful.

The fundamental concept is that a monad expresses the sequencing of computation. If you are forced to write all of your code in monadic style, then everything comes down to chaining monad objects together, where there are constraints on what you can hook up, based on types.

So the IO monad is a trick in which IO is exposed as an API of a state monad that models the entire state of the computer as a "RealWorld". So you have to write your IO code in monadic style. Then, magically, the compiler replaces the initial state with a fake object that serves no purpose except to force the sequencing of operations according to the types, and therefore perform things in the desired order, without actually having to pass around the "RealWorld" explicitly. I tried to illustrate something like this in the CoffeeScript code. The sequencing ensures that even in the presence of laziness, stuff happens in the right order.

The thing is, it is impossible to understand why this trick actually works unless you know what a monad is, what its laws are (preventing escapes), how the state monad works, and how IO is basically a special state monad. So I don't know a way around this required background of knowledge.

Let's take another example: when I was new to Ruby, I was completely bewildered by it. Remember, I was coming from C++ and Java. There was no way I could understand any of the magic of Rails or RSpec or what have you until I understood monkey patching, and I could not understand that until I understood that "methods" are message passing that is so dynamic that you can catch "method missing" and do all kinds of stuff. I think it would be fair to expect someone wanting to actually understand how Rails "magic" works to get down and dirty with the underlying semantic model of Ruby.

Granted, one can use Rails without knowing of all the magic, and just knowing informally what can be done, and that is true also of Haskell. I'm sure many people using Haskell have no clue how the IO monad is implemented. They just use it as an API, e.g. getLine :: IO String and putStrLn :: String -> IO () so you write code like an echo server main = getLine >>= putStrLn where all you have to know is that the API to get a string out of the IO system and into something else requires the >>= operator to hook up from getLine to something that takes a string and returns another IO monad object.

FranklinChen commented 10 years ago

I should also note that people are actively working on "principled" ways of doing IO, rather than using the monad hack, which is to implement impure code and pretend that it is pure. The general area of research is called "effect systems".

Also, more detail on the monad hack can be found here, if you're really curious: http://blog.ezyang.com/2011/05/unraveling-the-mystery-of-the-io-monad/

joelmccracken commented 10 years ago

I am, thanks, that is interesting.

Effect systems -- related to FRP? Sounds similar at least.

On Mon, Aug 11, 2014 at 10:32 PM, Franklin Chen notifications@github.com wrote:

I should also note that people are actively working on "principled" ways of doing IO, rather than using the monad hack, which is to implement impure code and pretend that it is pure. The general area of research is called "effect systems".

Also, more detail on the monad hack can be found here, if you're really curious: http://blog.ezyang.com/2011/05/unraveling-the-mystery-of-the-io-monad/

— Reply to this email directly or view it on GitHub https://github.com/FranklinChen/monad-scratchpad/issues/1#issuecomment-51866688 .

FranklinChen commented 10 years ago

Here is an extremely good article explaining things better than what I jotted down here: http://jelv.is/blog/Haskell-Monads-and-Purity/

Basically, that IO in Haskell is implemented using a monad is an implementation detail and not very interesting. More important, monads have nothing to do with state in general, but are an API technique, nothing fancier than that.

Again, I hope for a day in which IO and other state are modeled by something other than monads.

joelmccracken commented 10 years ago

This is really a good article. I enjoyed it, it clarifies things.

On Sat, Oct 4, 2014 at 9:02 PM, Franklin Chen notifications@github.com wrote:

Here is an extremely good article explaining things better than what I jotted down here: http://jelv.is/blog/Haskell-Monads-and-Purity/

Basically, that IO in Haskell is implemented using a monad is an implementation detail and not very interesting. More important, monads have nothing to do with state in general, but are an API technique, nothing fancier than that.

Again, I hope for a day in which IO and other state are modeled by something other than monads.

— Reply to this email directly or view it on GitHub https://github.com/FranklinChen/monad-scratchpad/issues/1#issuecomment-57923251 .