20-CS-4003-001 Organization of Programming Languages Fall 2017

Lambda calculus, Type theory, Formal semantics, Program analysis

Prev     Next     All lectures           Code


x // y = x >>= (\a -> y >>= 
(\b -> if b == 0 then Nothing 
                 else Just (a / b)))

{- the above in do notation
x // y = do
  a <- x
  b <- y
  if b == 0 then Nothing 
            else Just (a / b) 
  -   A monad is a construction that embeds a type system corresponding to a given type system into the underlying type system whereby it acts the same way and in place of the underlying type system. That is, all significant aspects of the underlying type system are preserved while new features particular to the monad are added.

The Monad is a type class over four functions as seen from executing

 Prelude> :info Monad
 class Monad m where
   (>>=) :: m a -> (a -> m b) -> m b
   (>>) :: m a -> m b -> m b
   return :: a -> m a
   fail :: String -> m a
These are named and defined as follows:
  1. >>= (Bind)
    An infix operator with polymorphic type
     (>>=) :: m a -> (a -> m b) -> m b
    The first argument has monadic type. The second argument is a function that maps from the underlying type of the first argument to another monadic type. The type of the result is in that other monadic type. Typically, the binding operation can be understood as having four stages:
    1. The monad-related structure on the first argument is interrogated to expose values in the underlying type a object
    2. The function (2nd arg) is applied to all of those values to obtain values of type m b
    3. The resulting values are interrogated exposing values of type b.
    4. The monad-related structure is reassembled over all of the results, giving a single value of type m b.

  2. >> (Bind)
    Same as above except there is no function on the right. The polymorphic type is
     (>>) :: m a -> m b -> m b
    This can be written as
     x >> y  equivalent to  x >>= (\_ -> y)
    For example:
     putStrLn "Hello" >> getLine ...

  3. return
    An identity function that maps a value in an underlying type to a value in the corresponding monadic type. The polymorphic type of return is
     return :: a -> m a
    The result is normally the "simplest" value in the corresponding type that completely preserves, in the context of the monad, the original value.

  4. fail
    Invoked when an error is to be reported. Has polymorphic type
     fail :: [Char] -> m a
    Usage: fail message-string

There must be a type constructor that defines, for every underlying type, how to obtain a corresponding monadic type. The name of the monad represents the type constructor. If m is the name of the monad and t is a data type, then m t is the corresponding type in the monad.

The Maybe data type is defined as a Monad like this

 data Maybe a = Nothing | Just a

 instance Monad Maybe where  
    Nothing >>= f = Nothing  
    Just x >>= f  = f x  
    return x = Just x  
    fail _ = Nothing 
The following axioms must be obeyed by any Monad:
  1. return acts as a neutral element of >>=
    1. (return x) >>= f is equivalent to f x
    2. m >>= return is equivalent to m

  2. Binding two functions in succession is the same as binding one function that can be determined from them. Thus:
     (m >>= f) >>= g
    is equivalent to
     m >>= (\x -> (f x >>= g))

Alternative do notation. Example:

 a = do 
   x <- [3,4]
   return x
 a = [3,4] >>= 
 (\x -> [1..4] >>= (\_ -> return x))
which works because lists are monads!! The above returns [3,3,3,3,4,4,4,4]. Here is what happens:
 [1..4] >>= (\_ -> return x)
means return value x for each object in [1..4] - but x is determined from the list [3..4]. The following:
 a = [3,4] >>= 
 (\x -> [1..4] >>= (\y -> return (x+y)))
returns [4,5,6,7,5,6,7,8]

Definition of the list type as a Monad:

 instance Monad [] where
   m >>= f  = concatMap f m
   return x = [x]
   fail s   = []

To the left is an implementation of a safe division operation