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

Lambda calculus, Type theory, Formal semantics, Program analysis

Prev     Next     All lectures           Code


import Control.Monad 

f = (\ x -> if (x == 0) then fail "zero" 
                        else Just (x+1))

v1 = Just 5 >>= f
v2 = Just 0 >>= f
v3 = Nothing >>= f
v4 = f 0
v5 = f 5

va = (return 3) :: Maybe Int
vb = (return 3) :: [Int]
vb = getLine >>= 
     (\x -> return (x ++ x)) >>= print

v6 = ap [(+1),(+2),(+3)] [1,2,3]

v7 = fail "test" :: Maybe Int
v8 = fail "test" :: Maybe [Int]
v9 = fail "test" :: IO ()

v10 = filterM (\x -> Just (x > 0)) 
              [2, 1, 0, -1]
(./.) :: Fractional a => a -> a -> Maybe a
x ./. 0 = Nothing
x ./. y = Just (x / y)

divide :: Fractional a => a -> [a] -> Maybe a
divide x ys = foldM (./.) x ys

v11 = divide 128 [2,4,8]
v12 = divide 8 [2,3,4,0,6,7]

v13 = guard True >> Just 3
v14 = guard False >> Just 3

v15 = liftM head (Just [23,24,25])
v16 = liftM tail (Just [23,24,25])

v17 = mzero :: [Int]
v18 = mzero :: Maybe Int

v19 = mplus "a" "b"
v20 = mplus (Just "a") (Just "b")
v21 = mplus (Just 10) (Just 20)
v22 = mplus mzero (Just 10)
v23 = mplus (Just 10) mzero

v27 = sequence [print 1, print 2, print 3] >>=
v28 = sequence [Just 1, Just 2, Just 3]

v29 = unless (0 == 1) (print "OK")
v30 = unless (1 == 1) (print "OK")
  -   If you have a value with a context, m a, how do you apply to it a function that takes a normal a and returns a value with a context? That is, how do you apply a function of type a -> m b to a value of type m a? So essentially, we will want this function:
 (>>=) :: (Monad m) => m a -> (a -> m b) -> m b  
Monads are just applicative functors that support >>= (called bind). The >>= operator either returns "Nothing" if it is passed "Nothing" on it's left-hand side; or if it's left-hand side is a "Just ..." it strips off the Just, and passes the contents into the function supplied on it's right-hand side. In the top examples to the left v1 and v5 have value Just 6; v2, v3, and v4 have value Nothing. The inferred type of f is f :: Integer -> Maybe Integer. See below for the meaning of fail.

The operator return is the second of the two basic operators of the Monad class (the other is >>=). The return operation takes a value from a plain type and puts it into a monadic container. The bind operation performs the reverse process, extracting the original value from the container and passing it to the associated next function in the pipeline. To the left, va has value Just 3, vb has value [3], and looking at vc then typing hello results in hellohello. The type of return is return :: Monad m => a -> m a.

The =<< operator (reverse binder) takes the contents of monad m and passes it to function f as a parameter. It may be useful when used as a parameter of a higher order function, or one can use it as a more readable way of coding, in some cases. Note: f =<< x = x >>= f. The type of =<< is (=<<) :: Monad m => (a -> m b) -> m a -> m b

The >> operator is essentially the same as (>>=), but does not pass the contents of the monad to the function specified as second parameter. It can be used to define the order in which actions take place. Note m >> k = (\_ -> k). The type of >> is (>>) :: Monad m => m a -> m b -> m b

The operator ap applies a function inside a monad to a value inside a monad of the same type. The value of v6 to the left is [2,3,4,3,4,5,4,5,6]. The type of ap is ap :: Monad m => m (a -> b) -> m a -> m b.

The operator fail is used when a condition is not satisfied. In the IO monad fail causes an interrupt. To the left, the value of v7 and v8 is Nothing and examining the value of v9 causes *** Exception: user error (test). The type of fail is fail :: Monad m => String -> m a.

The operator filerM filters out all elements of 2nd argument xs that do not fulfill the 1st argument predicate p, where p is a function that returns a value of type Monad m => m Bool. the result is a list inside a monad of the same type. For example, v10 to the left has value Just [2,1]. The type of filterM is filterM :: Monad m => (a -> m Bool) -> [a] -> m [a]

The operator foldM is the monadic version of foldl: that is, it takes a function of type (Monad m) => (a -> b -> m a). To the left the function ./. is defined to take care of divide-by-zero errors. The function divide uses foldM to repeatedly divide by a list of numbers. The value of v11 is Just 2.0 and the value of v12 is Nothing. The type of foldM is foldM :: Monad m => (a -> b -> m a) -> a -> [b] -> m a

The operator guard returns () if its argument is True, otherwise it returns mzero. The value of v13 is Just 3 and the value of v14 is Nothing.

The operator liftM lets a non-monadic function (1st argument) operate on the contents of a monad (2nd argument). To the left, v15 has value Just 23 and v16 has value Just [24,25]. The type of liftM is liftM :: Monad m => (a -> b) -> m a -> m b

The operator mapM applies a monadic function (1st argument) of type Monad m => (a -> m b) to each element of a list (2nd argument) resulting in a list inside a monad. The type of mapM is mapM :: Monad m => (a -> m b) -> [a] -> m [b]

The operator mzero is the zero of the MonadPlus class. To the left, the value of v17 is [] and the value of v18 is Nothing. Its type is mzero :: MonadPlus m => m a.

The operator mplus is the plus of the MonadPlus class. To the left, v19 has value "ab", v20 has value Just "a", v21 has value Just 10, v22 has value Just 10, v23 has value Just 10.

The operator sequence evaluates all monadic values in the input list from left to right and returns a list of the "contents" of these monads, placing this list in a monad of the same type. Evaluating can be interpreted as "performing an action", for example in the case of print. To the left v27 displays 1 2 3 [(),(),()], and v28 displays Just [1,2,3]. The type of sequence is sequence :: Monad m => [m a] -> m [a].

The operator unless executes a monadic expression (2nd argument) when the first argument evaluates to False. Looking at v29 shows "OK". The type of unless is unless :: Monad m => Bool -> m () -> m ()

The operator when executes a monadic expression (2nd argument) when the first argument evaluates to True. Looking at v30 shows "OK". The type of when is when :: Monad m => Bool -> m () -> m ()

Monads are useful in any situation where the programmer wants to carry out a purely functional computation while a related computation is carried out on the side. In imperative programming the side effects are embedded in the semantics of the programming language; with monads, they are made explicit in the monad definition, thus avoiding errors by action at a distance.