5 ms·
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
by danidiaz 13y ago
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-monadic-i-o http://stackoverflow.com/questions/17002119/haskell-pre-mona...
- dllthomas 13y agoA 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.
- Mithaldu 13y agoI'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?
- dllthomas 13y agoYou 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 ()
- tel 13y agoNope, 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.
- Mithaldu 13y ago> 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.
- dllthomas 13y agoThere 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-Monad.html#g:4 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.