On Sun, Jun 24, 2012 at 12:27 AM, Chris Dornan
<chris@chrisdornan.com> wrote:
* To move between functional and monadic code you have to completely
rewrite the code procedurally -- its
true and (IMHO) regrettable.
It's false. do-notation is completely optional. It merely makes it easier to extract multiple values from monadic actions, instead of the basic "one value per step" bind provides. Using join and (>>=) is just as easy as do-notation, once you understand the idiom.
A monad is, first and foremost, a functor. You can get at the underlying algebra while statically ensuring relevant properties, using its functorial or applicative or monadic interfaces.
For example: consider a function that parses a string into a Foo. It will have a type like
parseFoo :: String -> Maybe Foo
Should "useFoo" have the type
useFoo :: Maybe Foo -> Maybe Bar
or
useFoo :: Foo -> Bar?
The maybe functor/monad encapsulates the behavior of propagating possible-undefinedness, so we are entirely justified in using its functor/monad interface to simplify our types. There is no reason to redundantly have to pattern match on (Just foo) or (Nothing) when we can abstract the control structure away and do
useFoo <$> (parseFoo "Foo 1") -- (<$> == fmap)
or
(parseFoo "Foo 1") >>= return . useFoo
Expressing procedural code
functionally is as unnatural and error
prone as expressing functional code procedurally in my experience -- that
Haskell avoids compelling the programmer to
do either within its strongly-typed functional framework is (IMHO) its great
invention(*) and enduring strength.
Haskell didn't invent monads. They have been in use since Grothendieck's work in algebraic topology. At least! It is not hard to make a plausible case that the Pythagoreans had a theory of monads in mind 2500 years ago.