3 ms·
Perhaps the reason that Haskellers don't describe monads as "just sections of the program that are imperative" is because that statement is _not_ true. A monad
by naradaellis 16y ago
Perhaps the reason that Haskellers don't describe monads as "just sections of the program that are imperative" is because that statement is _not_ true.
A monad is a very nice container abstraction - period.
The IO part of Haskell just happens to leverage monads. One of the benefits of which is an explicit marking of impure methods in the type signature, but there are others.
Monads are used in plenty of purely functional parts of Haskell.
Disclosure: been programming Haskell for only a few months now, so someone pull me up if I'm wrong. However, I have used a lot of monads so far (and they're not hard, its just a higher, more convenient level of abstraction).
edit: to address your post further. I honestly don't think that the community is the reason that Haskell isn't taking off. If you were to gather stats on the points at which would-be Haskellers give up, I think most people would leave 1) when they can't grok the syntax easily or 2) when they can't get tools or libraries going easily (it was a problem for me) and long before they get to the point of visiting the news groups and start running up against academic-type people.
- tkahn6 16y agoCan you give an example of where monads are not used to interact with stateful things? That would be helpful to me.
- jamii 16y agoPFP uses monads to represent probability distributions. http://web.engr.oregonstate.edu/~erwig/pfp/ http://web.engr.oregonstate.edu/~erwig/pfp/
- naradaellis 16y agoI don't know how familiar you are with Haskell... but anyway: Say you're working with the Maybe type, which is often used to represent operations that might fail, such as a map lookup, for example. data Maybe a = Just a | Nothing We're using two functions defined like so (feeling unimaginative at the moment, forgive me): x :: String -> Maybe String y :: String -> Maybe String We want to use them together. Someone who's not familiar with monads might write something like this: myFunction text = case x text of (Just newText) -> y n Nothing -> Nothing (If x works and returns a value, put that value into the y function. If x didn't work, just return Nothing) It works fine, but imagine you had 3 functions that returned Maybes, it would get tiresome and messy nesting all those case statements endlessly. [...] case x text of Just newText -> case y newText of [...] Not being satisfied with boilerplate, lets make an operation that will simplify this a bit: bind :: Maybe a -> (a -> Maybe b) -> Maybe b bind (Just x) f = f x bind Nothing _ = Nothing now we can define myFunction like so: myFunction text = (x text) `bind` y if we want to add another operation: myFunction text = (x text) `bind` y `bind` z Congratulations you've mostly made a monad. Bind is one of the monad operators (>>=), the other operators are extremely trivial to implement for the Maybe type. This is why we say a monad is just a container with some handy operators. Maybe is the container, and bind is a way to chain together operations (without explicitly taking the value out of the container) so the operators themselves don't have to know anything about the nature of what they're dealing with. I won't bang on anymore, this is a longer, better written tutorial[1] in the same vein as this short summary. [1]: http://blog.sigfpe.com/2006/08/you-could-have-invented-monads-and.html http://blog.sigfpe.com/2006/08/you-could-have-invented-monad...
- tkahn6 16y agoI appreciate that. I am actually familiar with Haskell and the Maybe monad. Are there use cases for Maybe where you're not interacting with some sort of IO?
- naradaellis 16y agoOh yeah sure all the time, Maybe shows up a lot. It becomes more useful and less of a pain once you realise you can deal with it using monad operators. From the standard library a list operator and a map operator: elemIndex :: a -> [a] -> Maybe Int lookup :: k -> Map k a -> Maybe a Say we have a map of lists of string, for some reason. We need to find the index of the element "foobar" in a particular key, so you could write: lookup key map >>= elemIndex "foobar" (a simple example for the sake of brevity) Not very impressive, but monads aren't anything groundbreaking after all, they're just utilities that make our lives easier. There are more complicated operations that come in handy later, but they are quite straightforward once you get a grasp of the container metaphor.
- tkahn6 16y agoAh duh. That makes sense. Would it also make sense to use Maybe monad for converting a [Char] to an Integer? stringToInt :: [Char] -> Maybe Integer
- naradaellis 16y agoYeah it would. I think there was a Real World Haskell exercise that involved that actually.
- jrockway 16y agoThe Maybe and List monads have nothing to do with state, and are very common in programs. Let's use the List monad to determine someone's roommates. > import Control.Applicative > import Data.List First, the data: > type Person = String > type Address = String > addresses :: [(Person, Address)] > addresses = [("jrockway", "123 Fake St."), ("jrockway's cat", "123 Fake St.")] > people :: [(Address, Person)] > people = uncurry (flip (,)) <$> addresses And some helper functions around this data, a function to return all addresses for a person, and a function to return all people that live at a certain address: > assocFilter :: Eq a => a -> [(a,b)] -> [b] > assocFilter p xs = snd <$> filter ((==p) . fst) xs > addressesForPerson person = assocFilter person addresses > peopleAtAddress address = assocFilter address people To find a person's roommate, we have to chain two computations. First, we have to find zero or more places where a person lives. Then we need to find who else lives at each of those addresses. With the List monad, this is not much code! > roommatesFor :: Person -> [Person] > roommatesFor person = do > address <- addressesForPerson person > peopleAtAddress address The monadic combinator >>= (which is hidden by do) does all the looping for us, so we don't have to explicitly write it out. BTW, you can just cut-n-paste this into a .lhs file and run it, if you want to try it out.
- chc 16y agoHere's a common example of a monad being used in a non-stateful way: map (* 2) [1,2,3,4] Yep, that's a function on a monad — lists are monads. The same function can be written: [1,2,3,4] >>= return . (* 2)