Friday, February 15, 2013

HASKELL MONADS

HASKELL MONADS

REVISED: Wednesday, January 24, 2024




Haskell Monad.

The monad serves as the glue which binds together the actions in a program.

I.  FUNCTIONAL VERSUS IMPERATIVE

In functional programming, code is just like data; code and data are the same. In imperative programming, code and date, are two different things. For example, imperative programmers often access a function's data, via "table look ups".

The term "monad" comes from "category theory", which is a branch of algebra; or, depending on whom you talk to, algebra is a branch of "category theory."

Eugenio Moggi introduced the idea of using monads for programming in 1988, around the time the Haskell 1.0 standard was being developed. Many of the functions in today's Prelude date back to Haskell 1.0, which was released in 1990. In 1991, Philip Wadler started writing for a wider functional programming audience about the potential of monads, at which point they began to see some use. Not until 1996, and the release of Haskell 1.3, did the standard acquire support for monads.

Functional programming is not difficult; you do not need to know "category theory" to program "shared mutable state" with functions using  Haskell monads. Haskell functions are first-class data types, meaning that Haskell programs can work with them just as well as they can work with any other type of data.

x : int                   -- Asserts function x has type int.

f : int -> int      -- Asserts function f is a thing that takes an int and gives you an int.

x : a                      -- Asserts function x has type a, which is a generic, any type.

f : a -> a            -- Asserts function f takes an a of any type and gives you an a of any type.

g : a -> a           -- Asserts function g takes an a of any type and give you an a of any type.

We can combine the two functions f and g shown above.

One way would be to call the function g on a variable a of type a; for example, g(a); then call the function f on that result; for example, f(g(a))

Another way would be to call the function f on a variable a of type a; for example, f(a); then call the function g on that result; for example, g(f(a))

In Haskell, calling a function is the same as function application.

g a        -- Function application in Haskell; calling the function g with an argument of type a.

g(f a)  -- Calls function f first and then calls function g.

f(g a)  -- Calls function g first and then calls function f.

Function composition: composing two functions produces a new function that, when called with a parameter, a, is the equivalent of calling g with the parameter a, and then calling f with that result.

(f o g) a = f (g a)    

The little circle o is called function composition; it is a generic composition operator. The notation (f o g) is read as "f composed with g" or just "f of g". Composition operators are studied in the field of "operator theory".

Prelude>  :type (.)
(.) :: (b -> c) -> (a -> b) -> a -> c
Prelude> 

(f o g) = h

(f o g) = h : a -> a     -- The function h takes an a of any type and give you an a of any type.

II.  MONOID

Functions under composition are a monoid.

A monoid is a set or collection of things, plus a rule for combining those things, and that rule obeys some rules. 

One of the biggest problems in software today is controlling complexity. The world of side effects is very complicated. Monoids are the way to build complexity. Monoids allow you to create complexity starting with simplicity. We started with two functions and created a third function of the same type; i.e.:

f  : a -> a            
g : a -> a            
h : a -> a     

Compositionality is the way to control complexity.

Examples of monoids:

(+)     and 0
(*)     and 1
(||)    and False
(&&) and True
(++) and []
(>>) and done

III.  MONOID EXAMPLE

Consider a clock. The numbers on a clock form a monoid. The rule for combining them is take one number from the clock x, add another number from the clock y, and then cast out 12s; for example:

(x + y) % 12     -- % is "modulus" which in this case means the remainder after dividing by 12. 

(7 + 10) / 12 = 17/12 = 1 twelve and a remainder of 5. 

Prelude> (7 + 10) `mod` 12     -- `mod` is a modulus operator.
5
it :: Integral a => a
Prelude>

Prelude> (7 + 10) `rem` 12     -- `rem` is a modulus operator.
5
it :: Integral a => a
Prelude>

A. ASSOCIATIVITY

It does not matter how you group the applications; function composition is always associative.

⊕ (y ⊕ z) = (x ⊕ y) ⊕ z

(f o g) o h = f o (g o h)     -- (g o h) = g (h a) and  o (g o h) = f ( g(h a) )

B. EXISTENCE OF A UNIT OR A ZERO

The monoid must contain a special member such that:
 ⊕ 12 = x            -- In the clock example, 12 represents a "special member".
12 ⊕ x = x

There is a special function that lives in the monoid called id.


id : a -> a
id a = a

(f o id) = f (id a)
            = f a

In Haskell unit is:


return : a -> Ma

C. COMMUTATIVITY


A monoid does not have to satisfy the law of commutativity.

x ⊕ y != y ⊕ x 


f(g a) != g(f a)          -- For example, sin cos not same as cos sin.

If you are going to nest function calls, the types must line up; then compositionality makes sense.

IV.  MONADS

x : a

f : a -> Ma          -- Ma is a type constructor which creates a function of a generic type.            
g : a -> Ma         -- The function g takes an a and returns a Ma            
h : a -> Ma
>>= : a -> Ma     

\a -> [ (f a) >>=  \a -> (g a) ]        -- A function of a that does f a; >>= is  bind or shove
          Ma             a -> Ma            -- Ma is data living in a monad; or functions live in a monoid.

\a -> [ Ma >>=  a -> Ma ]

>>= ensures your functions are compositional.

g : a -> b
f : b -> c
(f o g) : a -> c

(f o g) a = f (g a)

V. CONCLUSION

In this tutorial, you have received an introduction to Haskell monads.

VI. REFERENCES

Brian Beckman: Don't fear the Monad.