Definition of a Monad

A monad is just a monoid in the category of endofunctors, what’s the problem?

A monoid is…

  • A set, S
  • An operation, • : S × S -> S
  • An element of S, e : 1 -> S

Examples:
0 + 7 == 7 + 0 == 7
(• ≡ +, S ≡ Natural Numbers, Identity ≡ 0)

[] ++ [1,2,3] == [1,2,3] ++ [] == [1,2,3]
(• ≡ ++, S ≡ [Int], Identity ≡ [])

{} union {apple} == {apple} union {} == {apple}
(• ≡ union, S ≡ {fruits}, Identity ≡ {})

…satisfying these laws:

  • (a • b) • c = a • (b • c), for all a, b and c in S
  • e • a = a = a • e, for all a in S

A monad is…

  • An endofunctor, T : X -> X
  • A natural transformation, μ : T × T -> T, where × means functor composition
  • A natural transformation, η : I -> T, where I is the identity endofunctor on X

…satisfying these laws:

  • μ(μ(T × T) × T)) = μ(T × μ(T × T))
  • μ(η(T)) = T = μ(T(η))

Tying it all together

  • a monad is a structure that defines a way to combine functions,
  • analogously to how a monoid is a structure that defines a way to combine objects,
  • where the method of combination is associative,
  • and where there is a special ‘No-op’ that can be combined with any Something to result in Something unchanged.

(Full article: http://stackoverflow.com/questions/3870088/a-monad-is-just-a-monoid-in-the-category-of-endofunctors-whats-the-problem)

fold vs map

Today I learned that map can be implemented in terms of fold, i.e. if we have fold (reduce) we already have map.

The source code for foldr is:

foldr f z []     = z
foldr f z (x:xs) = f x (foldr f z xs)

So, we can do something like:

Prelude> foldr ((:).(+1)) [] [1,2,3]
[2,3,4]

Instead of using (+1) here, we can compose any function.

We can also do

Prelude> foldr (+) 0 [1,2,3]
6

The beauty of fold is that for a given data of type A, it can return data of type B.
While for map, for a given data of type A it will always return data of type A.

As we’ve shown, fold can return a list, a number, or anything else that we specify. But this is not the case with map.

The reason is that fold has a more generic morphism (catamorphism), and this is what makes it more powerful than map (homomorphism).

Here are some examples:

Prelude> foldr ((++)) [] ["hello", "world"]
"helloworld"
Prelude> foldr ((++).(words)) [] ["hello world", "I am fine"]
["hello","world","I","am","fine"]

And for something more complex:

parsePackets :: String -> [String]
parsePackets [] = []
parsePackets x = a:parsePackets b
where
(a,b) = splitAt 4 x

*Main> parsePackets "hey test 123 packets aligned in 4 bytes"
["hey ","test"," 123"," pac","kets"," ali","gned"," in ","4 by","tes"]

And here’s an analogous example with fold:

*Main> fst $ foldr (\x (chunks,partial) -> if length partial == 3 then
((x:partial):chunks,"") else (chunks,x:partial)) ([],[])
"hey test 123 packets aligned in 4 bytes"
[" tes","t 12","3 pa","cket","s al","igne","d in"," 4 b","ytes"]
Prelude> foldr (\x (chunks, partial, all, cnt) -> if x == 3 || cnt == 3 then
(x:chunks, partial, x:all, cnt+1) else (chunks, x:partial, x:all, cnt+1))
([],[],[],0) [1,2,3,4,5,6,7,3]
([3,5,3],[1,2,4,6,7],[1,2,3,4,5,6,7,3],8)

So we can notice that it is quite analogous to an imperative loop, i.e. we can look at fold’s accumulator as a local variable.

We can also implement a fixed point combinator using fold, proving that iterations can be reduced to folds:

fix f = foldr (\_ -> f) undefined (repeat undefined)

The undefined is just a gap-filler. The expression ‘repeat undefined’ generates a list of unbounded length. We don’t care about its elements, so anything will do. The fact that the list is infinite means that we get as many applications of the f parameter as we need. Note that, because the list is infinite, foldr will never reach the empty list, so it does not matter what value we give for the base case argument. Nonetheless, the type-checker requires that the argument has a polymorphic type, so it is quite convenient to use undefined here also.1

So, now we can experiment some more with recursion:


Prelude> let fix f = foldr (\_ -> f) undefined (repeat undefined)
Prelude> let fact x = if x == 0 then 1 else x * fact (x-1)
Prelude> (fix (\x -> fact)) 4
24

1. Pope, Bernie. “Getting a Fix from the Right Fold“. The Monad.Reader (6): 5–16.

Understanding Monads boxing

Today on #haskell@freenode I had an interesting discussion. It all started when I asked if the following statements make any sense:

Just 5 >>= \x -> Just $ x+1
what this does is basically unwraps Just, adds 1 to its value and returns Just. (*
return (Just 5) >>= \y -> y >>= \x -> Just $ x+1
what this does is basically unwraps the monadic value of Just 5, so we have Just 5.
So we have return (Just 5) >>= \y -> y == Just 5. Now (*) applies here.

Let’s check the types:

Prelude> :t Just 5
Just 5 :: Num a => Maybe a
Prelude> :t return (Just 5)
return (Just 5) :: (Monad m, Num a) => m (Maybe a)

So, basically, my question was (as can be seen from the statement above), how is it possible to convert m (Maybe a) to Maybe a? And, if m (m a) -> m a is possible, why isn’t m a -> a possible?

Well, m a -> a can be possible for some monads, for example for the Maybe monad, if we define it like:

fromJust (Just x) = x

But it’s not something that can be easily implemented for just any monad.

Now, as for why m (m a) -> m a is possible (and, in general m (m (… (m a) …)) -> m a), we can take a look at the definition of join, which is:

join x = x >>= id

So, if we try to do something like this:

Prelude> join $ Just (Just 5)
Just 5
Prelude> :t Just (Just 5)
Just (Just 5) :: Num a => Maybe (Maybe a)
Prelude> :t Just 5
Just 5 :: Num a => Maybe a
Prelude> join $ Just (Just 5)
Just 5
Prelude> :t join $ Just (Just 5)
join $ Just (Just 5) :: Num b => Maybe b

We can see basically how it “unboxes” stuff, and in my statement above I implicitly used join, which is the underlined part.

But how does it really work?

Well, if we look at the type of the bind operator:

Prelude> :t (>>=)
(>>=) :: Monad m => m a -> (a -> m b) -> m b

We can now start experimenting. What if we set a = m c?

We get m (m c) -> (m c -> m b) -> m b. Can we find such a function that satisfies this?

For (a -> m b) we can basically use the following lambda \x -> return x
So, for (m a -> m b), what if we omit return, and instead try \x -> x?

Prelude> Just (Just 5)
Just (Just 5)
Prelude> Just (Just 5) >>= \x -> x
Just 5
Prelude> :t Just (Just 5) >>= \x -> x
Just (Just 5) >>= \x -> x :: Num b => Maybe b
Prelude> :t Just (Just 5)
Just (Just 5) :: Num a => Maybe (Maybe a)
Prelude> :t (Just 5)
(Just 5) :: Num a => Maybe a

So, by using return, in the example of m a -> (a -> m b) -> m b we give back a “boxed” value, because we have \x -> return x where x = a, and return x = m a.

But, by not using return in the example of m (m a) -> (m a -> m b) -> m b we give back the same value that we receive, because we have \x -> x where x = m a, and the lambda expression will evaluate to m a.

So, with this we have shown how it’s possible to convert m (m a) to m b, and thus in general m (m (… (m a) …)) to m b.

Some interesting excerpts from the chat (please note that some parts are removed):

 the difference between "return $ Just 5" and "Just 5" is that the first is a monadic value
(instance of Monad), and the second is only instance of data Maybe?
BoR0: Maybe is an instance of Monad, the difference is this:
> return $ Just 5 :: [Maybe Int]
[Just 5]
> return $ Just 5 :: Maybe (Maybe Int)
Just (Just 5)
BoR0: Maybe is an instance of Monad, "Monad m => m" says "any monad will work"
BoR0: So "(>>=) :: Monad m => m a -> (a -> m b) -> m b" says it'll work for *any* Monad,
even if if you don't know yet which one
BoR0: There's no reason why a monad cannot contain another monad inside
> return 5 :: [Int]
[5]
aha, okay. so return $ Just 5 is doubly "wrapped"
BoR0: Yes
BoR0: ^
so if we have return x = Just x for Maybe monad, why doesn't return $ Just 5 give Just (Just 5)
to us?
BoR0: It will, if you ask for it
> return (Just 5) :: Maybe (Maybe Int)
Just (Just 5)
but what does it do without specifying :: ... ?
BoR0: Without the type signature it's polymorphic, it can be any Monad instance
polymorphic! that clarifies it! great
BoR0: Yes, all typeclasses are polymorphic, unless you specify a type OR type inference sees
which type you wanted (actually, this is the only way, the type annotation just explicitly tell the
type inference what you want :)
I somewhere read that IO String can't be converted to String. but with this discussion I think
the opposite, what is wrong now?
so what held for Maybe monad (extracting x from Just x) doesn't necesarilly hold for IO monad?
BoR0: For Maybe, you weren't really extracting. You were putting the value back into a Just
at the end with return. All monadic expressions have a return at the end.
BoR0: Yes, some *specific* monads may provide tools for extracting values (i.e. Maybe
and list, for example). But the generic monad class does not provide a way to do that
BoR0: Since IO doesn't provide a function to extract values, there's no way to get them out
BoR0: monads allow you to go from an arbitrary number of applications of M to A to just M A

Functors

In Haskell, the Functor instance is only supposed to handle the mapping between objects, under the following rules:

1. Identity (fmap id = id)
2. Composition fmap f . fmap f = fmap (f o g)

So, if we want to declare a Functor instance over some type, that’s all we need to care about.
Functors are nothing more than that (to handle fmap for some actual type). The type definition of fmap is:

fmap :: Functor f => (a -> b) -> f a -> f b

So, from this we can see that the first parameter is a morphism, and the second parameter is the actual object. So, for instance, we can have:

fmap floor [1.5, 2.5, 3.5]

And we can see how our list “morphs” from a list with doubles to a list with integers!

Prelude> :t [1.5, 2.5, 3.5]
[1.5, 2.5, 3.5] :: Fractional t => [t]
Prelude> :t [1, 2, 3]
[1, 2, 3] :: Num t => [t]
Prelude> :t fmap floor [1.5, 2.5, 3.5]
fmap floor [1.5, 2.5, 3.5] :: Integral b => [b]

Another interesting thing to have a look at is the instance for ((->) r), which is defined as:

instance Functor ((->) r) where
    fmap f g = (\x -> f (g x))

Now, by having this definition, and that of fmap’s, we can apply ((->) r) to fmap to get:


fmap :: Functor f -> (a -> b) (r -> a) (r -> b)
fmap f g = (\x -> f (g x))

So, with this we can see that we can apply fmap to functions too!


Prelude> fmap (* 123) succ 3
492
Prelude> fmap (* 100) (\x -> x + 1) 123
12400

And, for some more theory (if you care), Wikipedia states that Functors are morphisms, and for morphisms:

In many fields of mathematics, morphism refers to a structure-preserving mapping from one mathematical structure to another. The notion of morphism recurs in much of contemporary mathematics. In set theory, morphisms are functions; in linear algebra, linear transformations; in group theory, group homomorphisms; in topology, continuous functions, and so on.
In category theory, morphism is a broadly similar idea, but somewhat more abstract: the mathematical objects involved need not be sets, and the relationship between them may be something more general than a map.

Music fun

Here is a tiny example that I’ve been playing around with the other day:

data Note = C | D | E | F | G | A | B deriving (Show, Enum, Bounded, Eq, Read)

buildTuple :: [a] -> [(Maybe a, Maybe a)]
buildTuple xs = zip z $ Nothing:z
where
z = map Just xs

getPreviousElement :: [Note] -> Maybe Note
getPreviousElement [] = Nothing
getPreviousElement xs = snd $ last $ buildTuple xs

addNote :: [Note] -> [Maybe Note]
addNote xs = map Just xs ++ [getPreviousElement xs >>= succNote]

succNote :: Note -> Maybe Note
succNote n
| n == maxBound = Just minBound
| otherwise = Just $ succ n

parseBrackets :: String -> String
parseBrackets ('{':xs) = '[' : parseBrackets xs
parseBrackets ('}':xs) = ']' : parseBrackets xs
parseBrackets (x:xs) = x : parseBrackets xs
parseBrackets x = x

main :: IO [Maybe Note]
main = getLine >>= \xs -> return (addNote (read (parseBrackets xs) :: [Note]))

This example demonstrates a couple of things:

1. How we can use the Haskell’s type system to define a list of Notes
2. The use of the zip function, to show how easy it is to get a previous element in a list (what buildTuple does is e.g. for [A,B,C] it would produce [(Just A, Nothing), (Just B, Just A), (Just C, Just B)], so that we have a track of previous elements)
3. It demonstrates reading and playing around with IO and parsing stuff on our own way