FW: RE [Haskell-cafe] Monad Description For Imperative Programmer
Dan Weston
westondan at imageworks.com
Wed Aug 1 16:32:53 EDT 2007
> The outermost monad (rightmost bound function) is in the driver seat,
and is absolutely free to ignore the monad to its
> left (which in turn encloses monads to its left)! This includes of
> course the main input IO () monad. Don't believe me?
>
> Prelude> const 3 (return "Nuclear waste leaking..." >>= print) + 5
> 8
>
> Phew, no nuclear waste leaked after all. What a relief!
No, I don't believe you.
It's true that the right monad instance can ignore its left sibling
(same monad of course, just a different instance) to allow backtracking
(the Const monad being a trivial example of this), but IO is not such a
monad.
Your example just shows that monad instance expressions (like any
Haskell expression) are evaluated lazily in Haskell.
I am relieved though, that no nuclear waste was leaked by your example.
Dan Weston wrote:
> Here's my rant about the way monads are explained in Haskell tutorials
> (which are much too polluted with nuclear waste to be safely approached):
>
> It is a big mistake to start with the IO monad. It pollutes and
> misdirects the understanding of what a monad is. The dreaded "nuclear
> waste" metaphor is actually a red herring, having nothing do do with a
> monad at all, merely the artifact of the absence of an exit function in
> the IO monad (which actually does exist and is called unsafePerformIO,
> but that is a secret. Shhh...), combined with Haskell's refusal to work
> for free.
>
> Monads are required to have an extrance (reification/constructor
> function) called return. They are *not* required to have an exit
> (reflection/deconstructor function).
>
> They *do* combine (bind) together like links in a chain, which is not a
> list but an equivalence class of trees, where the only thing that
> matters is the order of the leaves, so unlike a list you don't have to
> start at the tail and assemble one-by-one. [Actually, the compiler picks
> just one of these trees (the singly-linked list) but expects that all
> trees would evaluate the same.]
>
> They *do* bind only with flavors of themselves (State a cannot bind to
> IO b, though a monad transformer can merge the two). The output type of
> one monad instance must match the input type of another monad
> reification function (e.g. return) that it wants to bind to.
>
> In compensation for this tribalism, those snobby monads that want to
> clique off are out of luck: a monad cannot restrict what possible types
> can be used to construct a monad instance. That would be discrimination,
> and you must agree to accept all comers.
>
> Simple, no? Apparently not...
>
> Other things have nothing to do with monads per se gunk up the
> descriptions about monads:
>
> One red herring (the nuclear waste metaphor) refers to the fact since
> monads may or may not have an escape-clause (called variously runXXX,
> evalXXX, unsafePerformXXX), and IO in particular does not. The presence
> or absence of this has *nothing* to do with monads (only with IO),
> participates in no monadic laws, and shouldn't even be in the chapter on
> Monads. Whether nuclear waste seeps in (as in a State monad) or stays
> out (IO monad) has nothing to do with their monadic property and is a
> special property of those particular classes.
>
> Another even redder herring is the dreaded sequencing aspect. Monads do
> sequence *denotationally*, the way any nested closures sequence, which
> is exactly *backwards* from the naive understanding of sequencing:
> symbols defined to the left are in the *inner* scope, those to the right
> are in the *outer* scope. Perversely, when the symbols are evaluated,
> the rightmost monad is evaluated first. The leftmost monad in the
> program, the IO () passed in by main, is the *last* thing to be
> evaluated, not the first. The outermost monad (rightmost bound function)
> is in the driver seat, and is absolutely free to ignore the monad to its
> left (which in turn encloses monads to its left)! This includes of
> course the main input IO () monad. Don't believe me?
>
> Prelude> const 3 (return "Nuclear waste leaking..." >>= print) + 5
> 8
>
> Phew, no nuclear waste leaked after all. What a relief!
>
> This sequencing then has nothing to do with *operational* sequencing.
> When the symbols are evaluated is the basic call-by-need data-dependent
> stuff of most Haskell symbols and again, has nothing to do with monads.
>
> I learned about the IO monad first and I regret it bitterly. It cost me
> a years' worth of misunderstanding. I misapprehended that a monad had
> something to do with nuclear waste and never escaping the
> single-threadedness. I hope the new O'Reilly book doesn't make that
> mistake. Teach IO right away, but just don't call it a monad. IO is the
> exception, not the rule, in the menagerie of Haskell monads.
>
> How does all this map to C++? A monad is a a class, with no useful
> interface for the end user, that looks roughly (i.e. I haven't tested
> it) like:
>
> template <class M, class T>
> class Monad
> {
> public:
>
> virtual ~Monad() {}
>
> // return
> Monad(T t) : t_(t) {}
>
> // bind operator (>>=), where
> // F :: Monad<M,T> -> (T -> Monad<M,U>) -> Monad<M,U>
> virtual template <class U> Monad<M,U>
> operator>>(typename U::F f) = 0;
>
> private:
> T t_;
> };
>
> C++ programmers will immediately see past the syntactic kruft to notice
> that
> 1) the constructor arg is not a value but an unevaluated function
> object, that starts out unevaluated.
> 2) The result of m >> f is a monad object, totally unevaluated.
> 3) There is no member function to do anything with the monad at all! As
> is, it is useless.
>
> Derivers of this class will naturally want to add such functionality:
>
> template <class M, class T>
> class MyMonad : public Monad<M,T>
> {
> // The parent class needs to know what type of monad
> // this can bind to
> typedef someUnaryFunctionObjectTypeReturningB F;
>
> // There is no input, just an output!
> // The input is via the constructor arg of the innermost monad
> B operator()() { ... start the ball rolling ... }
> };
>
> Non-C++ programmers will be stunned that the above garbage can be
> understood by anyone, compared to the simplicity of type classes in
> Haskell. When all you have is a hammer...
>
> The moral of the story is that monads are less than meets the eye. You
> can create them and concatenate them, but may not be able to do anything
> with them (some monads do let you, some don't), though the runtime
> system agrees to evaluate one special monad exactly once.
>
> What the rightmost monad does with its internals (including all
> inner/left monads bound to it) has nothing to do with monads whatever,
> except for the minimal requirement that they agree to be bound only to
> other monads like themselves, and that as a group they all agree to not
> form a clique (i.e. they are associative).
>
> What could be simpler that that? No please, no more nuclear waste! :)
>
> Dan
>
> peterv wrote:
>> Kaveh> "A monad is like a loop that can run a new function against its
>> variable in each iteration."
>> I’m an imperative programmer learning Haskell, so I’m a newbie, but
>> I’ll give it a try ☺ Making mistakes is the best way to learn it ;)
>>
>> There are lots of different kinds of monads, but let’s stick to the IO
>> monad first, which you seem to refer to.
>>
>> No *an IO monad is not a loop at all*. Instead, from an imperative
>> programmer’s point of view, the following might be better:
>>
>> “an IO monad is a delayed action that will be executed as soon as that
>> action is needed for further evaluation of the program.”
>>
>> The simple program
>>
>> main = getLine >>= putStrLn
>> can be visually represented as (see attachment)
>>
>> The “world” (=a representation of your computer’s hardware) is passed
>> to the main function, which passes it to all actions that it
>> encounters during its lazy evaluation, causing the executing of the
>> actions as an effect.
>> The red wire through which the “world flows” is a “single thread”, it
>> cannot be split (because the physical world cannot be copied!!!), so
>> no unwanted side effects can ever occur, making IO safe in Haskell.
>> When you write your IO program, this world object is never available
>> (the IO type is a special internal type), so the red wire is erased
>> from the diagram, and the getLine and putStrLn boxes become “delayed
>> actions”.
>> Imperative programmers like myself might initially be confused when
>> they see Haskell’s do notation, because it looks like the actions are
>> strict statements as in C/C++/Pascal/Java/C#/etc, but they are not.
>>
>> For example, try the following program:
>>
>> main = do last [
>> putStrLn "NOT executed although it is first in the list, as
>> it is not used by the main function!",
>> putStrLn "This action IS executed because it is evaluated
>> by the main function." ]
>>
>> This is of course all due to Haskell’s laziness which only evaluates
>> just those expressions that it needs to evaluate the main function.
>>
>> One thing to note in the diagram above is that the getLine box has TWO
>> outputs, the String and the World. But functions can only have a
>> single output, but this can be tuple. Hence the passing of the world
>> from one box to the other is a bit more complicated. It is this
>> pattern of extracting both values from the output and passing them to
>> the next function and other related combinations that form the generic
>> monad class, which can be used for many more things than IO.
>>
>> See http://haskell.org/haskellwiki/IO_inside for a much deeper and
>> more correct explanation ☺
>>
>> And for the pros here, did this newbie make any sense? Probably not ;-)
>> Oh no, yet another monad explanation!!! Now the universe will most
>> certainly collapse…
>>
>> No virus found in this outgoing message.
>> Checked by AVG Free Edition. Version: 7.5.476 / Virus Database:
>> 269.11.0/929 - Release Date: 31/07/2007 17:26
>>
>>
>>
>> ------------------------------------------------------------------------
>>
>>
>> ------------------------------------------------------------------------
>>
>> _______________________________________________
>> Haskell-Cafe mailing list
>> Haskell-Cafe at haskell.org
>> http://www.haskell.org/mailman/listinfo/haskell-cafe
>
>
More information about the Haskell-Cafe
mailing list