News for hackers. Stuff that matters.
Re:A Gentle Intro to Monads … Maybe? by Mithaldu on Friday January 17, 2014 @11:49AM (#7076738)
How does a complete Haskell program using non-monadic IO look like?

As for "most other Haskell monads", from what i can tell they're just wrappers around the core monads with additional functionality tacked on and i consider it lazy to also call them monads instead of wrappers.

Re:A Gentle Intro to Monads … Maybe? by danidiaz on Friday January 17, 2014 @12:08PM (#7076904)
Not really, they are independent of IO (you may be thinking of monad transformers, which are ways to extend an existing monad.)

For example, this is the entire definition of the Maybe monad:

    data  Maybe a  =  Nothing | Just a
      deriving (Eq, Ord)
    
    instance  Functor Maybe  where
        fmap _ Nothing       = Nothing
        fmap f (Just a)      = Just (f a)
    
    instance  Monad Maybe  where
        (Just x) >>= k      = k x
        Nothing  >>= _      = Nothing
    
        (Just _) >>  k      = k
        Nothing  >>  _      = Nothing
    
        return              = Just
        fail _              = Nothing
It's just a way to propagate failure when sequencing computations. (That's why the "Nothings" are always followed with more "Nothings" in the definition.)

This SO question describes Haskell's pre-monadic IO: http://stackoverflow.com/questions/17002119/haskell-pre-mona...

Re:A Gentle Intro to Monads … Maybe? by Mithaldu on Friday January 17, 2014 @12:15PM (#7076961)
I'm beginning to see how my definition is wrong. Right now it seems to me like the simple definition of a Monad is: It's a prettied-up workaround.

A bit i think i need to clarify: In my opinion most monad explanations fall entirely flat because they explain WHAT a monad does, but NEVER explain WHY they were created in the first place; making the whole exercise somewhat akin to mathematics teaching in us-american schools.

With what all the responses pointed out it seems like monads get created when a pain point of a language is so often, and so consistently worked around in the same fashion; that someone decided to make an implementation of the workaround that looks like basic syntax; regardless of whether the implementation happens in core or in the language itself.

Thus for example Moose, a library that bolts object orientation syntax onto Perl, would probably also be a monad.

Am i still off-track?

Re:A Gentle Intro to Monads … Maybe? by danidiaz on Friday January 17, 2014 @12:31PM (#7077088)
In Haskell there is a kind of syntactic sugar called "do-notation" that simplifies working with monadic code and is bolted onto the core of the language. But it is not necessary, you can program with monads without it.

"It it seems like monads get created when a pain point of a language is so often, and so consistently worked around in the same fashion"

Well, pretty much. Here is a post about that: http://blog.sigfpe.com/2006/08/you-could-have-invented-monad...

Then there is the mathematical aspect to them, that can point to unexpected connections and new possibilities for abstraction.

Re:A Gentle Intro to Monads … Maybe? by Mithaldu on Friday January 17, 2014 @12:52PM (#7077243)
I'm not sure what to think about this answer. The first paragraph doesn't seem to address anything i said. The linked article seems to agree with my understanding, from the preamble, but contains too much Haskell syntax for me to ne able to understand what he's explaining, so i can't say for sure. And i know even less about the mathematical aspect.

However, still, thanks for letting me know that i might be moving in the right direction.

Re:A Gentle Intro to Monads … Maybe? by tel on Friday January 17, 2014 @12:29PM (#7077072)
Nope, definitely still off track. Typeclasses are a refactoring and abstraction tool used here, but monads are just an abstraction. They exist whether or not you reorganize your code. Even when you're using tuples and the like to implement state you still have a monad, you're just footing the bill on a bunch of complexity to implement it.

This the same as how people talk about javascript and C as "having monads in their semicolons". Semicolons do behave much like monads. They're just not first-class nor officially recognized as such.

Re:A Gentle Intro to Monads … Maybe? by Mithaldu on Friday January 17, 2014 @12:45PM (#7077184)
> Typeclasses are a refactoring and abstraction tool used here, but monads are just an abstraction. They exist whether or not you reorganize your code. Even when you're using tuples and the like to implement state you still have a monad, you're just footing the bill on a bunch of complexity to implement it.

I literally have no idea what any of that means. It does not seem in any way to explain why you disagree with my understanding.

For example:

> They exist whether or not you reorganize your code.

This seems like the definition of a non-sequitur to me. Replacing a few words, this sentence reads to me semantically the same as

"Anonymous subroutines exist whether or not you reorganize your code."

A true statement, but not one that conveys any previously unknown meaning.

Also please note that nothing you said addresses the WHY of monads.

Re:A Gentle Intro to Monads … Maybe? by tel on Friday January 17, 2014 @01:25PM (#7077467)
Monads don't have a why. They are simply a common pattern. Typeclasses enable polymorphism in Haskell and polymorphism allows for boilerplate reduction and code reuse. Monads can be factored out using typeclasses and usually are in Haskell. You use monads whether or not you're using Haskell and whether or not your language has built-in state manipulation. Certain types in Haskell are monadic and thus provide examples of functionality which shares that common pattern. Haskell exploits all of this in many ways. First, by tagging effects with types you have better documentation and safer programs. Second, by organizing many distinct types along their common monadic pattern you reduce boilerplate and provide a simple API. Third, by exploiting that API generically you build up a set of language constructs which operate "over all monads" which makes for a powerful construction kit. Fourth, by exploiting some algebraic structure that is a natural consequence of the generic pattern of monads you can decompose and recombine them into what are called transformer stacks.

Monads have no relation whatsoever to boilerplate reduction besides the fact that if you (a) notice their existence and (b) operate in a language with powerful enough generics then you can factor that common pattern to reduce boilerplate using that generics support.

If you recognize monads exist and don't have generics support you can still use the concept to better analyze your code and seek out ways of layering in new effects if desirable. You just won't reduce the boilerplate. This is the case with most languages which implement monads as a library, javascript, ruby, clojure, erlang.

Re:A Gentle Intro to Monads … Maybe? by Mithaldu on Friday January 17, 2014 @01:40PM (#7077584)
Well, since you refuse to use english on a level that can be understood by a reasonably well-taught non-american i can only tell you that while i have heard all the words you use before and understand their individual meanings, i have no idea what those sentences are meant to communicate when put together.

I give up.

Also, quite honestly, your claim that monads have no why makes me strongly question your understanding of the subject matter. Also see Einstein: http://www.brainyquote.com/quotes/quotes/a/alberteins383803....

I thank you for your efforts, but can only ask you to reconsider your approach.

Re:A Gentle Intro to Monads … Maybe? by dllthomas on Friday January 17, 2014 @07:43PM (#7079488)
"If you can't explain it, you don't understand it well enough" doesn't account for people who just suck at explaining.
Re:A Gentle Intro to Monads … Maybe? by dllthomas on Friday January 17, 2014 @07:15PM (#7079401)
There is a few ways you can speak of "the WHY of monads". Most basically, monads are one way of 1) combining things 2) which (may) produce a value, 3) where which things you combine in later may depend on earlier values produced.

Why do we speak of them, as opposed to just combining things in that way when we happen to? Partly, for the reasons people generally speak of design patterns: it's one fewer degree of freedom in your design which makes it easier to reason about and when others know the pattern it is easier to communicate what you are doing to them. In one-off cases, in most languages with (comparatively) limited powers of abstraction, this is most of what's useful about saying "hey, that's a monad!".

In Haskell, "Monad" is also an interface for things that fit that pattern, and we have a lot of functions that operate against that interface to do useful things, so that we don't need to rewrite those things for each new thing that happens to be a monad.

For instance:

    mapM :: Monad m => (a -> m b) -> [a] -> m [b]
which is like map, but takes a function that returns a monadic value instead of any function, and instead of producing a list of those monadic values it stitches together the values and gives you a wrapped list of the values. To drive intuition, we can specialize this for a few individual monads:

    mapM :: (a -> Maybe b) -> [a] -> Maybe [b]
Maybe. Pass it a function that may fail, and a list of values to feed into that function, and it will give you "Just" a list of the results or "Nothing" if any function fails.

    mapM :: (a -> Identity b) -> [a] -> Identity [b]
Identity. As you would pretty much expect, this is isomorphic to map. Not a lot of reason to do this unless you've got some other function you care about which is expecting something of this form and you want to basically pass map.

    mapM :: (a -> [b]) -> [a] -> [[b]]
List. The list monad is for nondeterminism - "take every path". I... don't immediately see a good use for mapM in list - something like concatMap is much more useful - but if you ever have a need for it...

    mapM :: (a -> IO b) -> [a] -> IO [b]
IO. Pass in a function that returns an IO action, and a list of parameters for that function, and give back an IO action that produces a list of the results. A simple example:

    mapM (\ l -> putStr (l ++ ": ") >> fmap (l,) getLine) ["height", "weight"]
This would have the type

    IO [(String, String)]
and would, when executed, prompt the user for height and weight in turn, and return a list of tuples containing both the label and the response. You can see how you could trivially add "age".

    mapM :: (a -> State s b) -> [a] -> State s [b]
State. State actions operate on an additional piece of data that's carried around and threaded through the chain of binds. This specialization of mapM takes a function that produces actions which use or modify state, threads them together into one big such action.

    mapM :: (a -> Parser b) -> [a] -> Parser [b]
Parser, from the wonderful attoparsec. Here, we pass in a function that generates parsers, and a list of inputs to that function, and get a parser that parses a list!

There are a ton more similarly abstract, comparably useful functions, some of which are in http://hackage.haskell.org/package/base-4.6.0.1/docs/Control... - and you can always write something new when there's a pattern you want to exploit for which a combinator doesn't exist. All of this - both the implementations of the monads (except the internals of IO) and the functions that operate on them - is written in ordinary Haskell. You can check out the source on Hackage, if you're curious as to how.

mapM is implemented:

    mapM f as = sequence (map f as)
If we inline sequence, that becomes:

    mapM f as = foldr k (return []) ms
      where
        k m m' = do { x <- m; xs <- m'; return (x:xs) }
We can strip out the do notation:

    mapM f as = foldr k (return []) ms
      where
        k m m' = m >>= (\ x -> m' >>= (\ xs -> return (x:xs)))
where it should be somewhat apparent there's not actually any voodoo.
Re:A Gentle Intro to Monads … Maybe? by samstokes on Saturday January 18, 2014 @05:12PM (#7082461)
Those first three paragraphs were a wonderfully clear summary. Thank you!
Re:A Gentle Intro to Monads … Maybe? by dllthomas on Saturday January 18, 2014 @06:18PM (#7082683)
Thanks!
Re:A Gentle Intro to Monads … Maybe? by dllthomas on Friday January 17, 2014 @06:01PM (#7079070)
You might be conflating monads with do-notation? Do-notation is a syntactic tweak to make using monads a little prettier, and is implemented in the language, but you can just as well use monads without it. Consider the IO example:

    main = getArgs >>= mapM_ putStrLn
where

    getArgs :: IO [String]
    putStrLn :: String -> IO ()
    mapM_ :: (a -> m b) -> [a] -> m ()
Re:A Gentle Intro to Monads … Maybe? by dllthomas on Friday January 17, 2014 @07:40PM (#7079480)
A lot of monads in the mtl (State, Writer, Reader, &c) are implemented by applying their transformer to Identity. Your point stands, as that's not the only way to implement them, isn't the way many other monads are implemented, and Identity itself is implemented just in Haskell code, but it's a possible source of some of the confusion.
Re:A Gentle Intro to Monads … Maybe? by dllthomas on Friday January 17, 2014 @05:41PM (#7078967)
Most monads for which you can implement a monad transformer are implemented by wrapping the monad transformer around Identity, but that's simply because you would otherwise be implementing basically the same thing twice. My impression has been that they were originally implemented directly and only transformer-ified later. Certainly, there is no reason that couldn't have been done. Identity doesn't involve any particular voodoo:

    newtype Identity a = Identity { runIdentity :: a }

    instance Monad Identity where
        return a = Identity a
        m >>= k = k (runIdentity m)

Haskell originally didn't include monadic IO - it was introduced in version 1.3, IIRC. IO looked like lazy streams of events, but it was pretty messy and pretty possible to deadlock, from what I hear. Writing modern Haskell, doing IO without any use of the IO type isn't possible, but you can - in principle - avoid ever using the fact that it's a monad by simply calling unsafePerformIO immediately on any IO action. Good luck actually ordering your IO operations, though.