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

Lambda calculus, Type theory, Formal semantics, Program analysis

    Prev     Next     All lectures           Code

Built-in Exceptions


divBy num = map (num `div`)

v1 = divBy 7 [1,2,3,4,5]
v2 = divBy 7 [1,2,3,4,0,5,6,7]

v3 = take 15 (map (\x -> 7 / x) [10,9..])

divBy1 _ [] = Just []
divBy1 _ (0:_) = Nothing
divBy1 num (den:xs) =
  case divBy1 num xs of
    Nothing -> Nothing
    Just res -> Just ((num `div` den) : res)

v4 = divBy1 7 [1,2,3,4,5]
v5 = divBy1 7 [1,2,3,4,0,5,6,7]
{- try divBy1 7 [1..] -}

divBy2 num dens =
    map worker dens
    where worker 0 = Nothing
          worker x = Just (num `div` x)

v6 = divBy2 7 [1,2,3,4,5]
v7 = divBy2 7 [1,2,3,4,0,5,6,7]
v8 = take 30 $ divBy2 7 [10,9..]

divBy3 _ [] = Right []
divBy3 _ (0:_) = Left "divBy3: divide by 0"
divBy3 num (den:xs) =
    case divBy3 num xs of
      Left x -> Left x 
      Right res -> Right ((num `div` den) : res)

v9 =  divBy3 7 [1,2,3,4,5]
v10 = divBy3 7 [1,2,3,4,0,5,6,7]
v11 = divBy3 7 [10,9..]

divBy4 num dens =
  map worker dens
  where worker 0 = Right "Hah!!"
    worker x = Left (num `div` x)

v12 = divBy4 7 [1,2,3,4,5]
v13 = divBy4 7 [1,2,3,4,0,5,6,7]
v14 = take 15 (divBy4 7 [12,11..])
  -   Haskell provides built-in exceptions. Illustrated here is the DivideByZero exception which is in the class of ArithExceptions. The div operator is used to trigger that exception in these examples since the / operator's zero division is handled internally. The divBy function to the left divides a given number by all the numbers in a given list. The type signature of divBy is this:
 
divBy :: Integral a => a -> [a] -> [a]
Sample output:
*Main> divBy 7 [1,2,3,4,5]
[7,3,2,1,1]

*Main> divBy 7 [1,2,3,4,0,5,6,7]
[7,3,2,1,*** Exception: divide by zero

*Main> take 20 $ divBy 7 [1..]
[7,3,2,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0]

*Main> divBy 7 [10,9..]
[0,0,0,1,1,1,1,2,3,7,*** Exception: divide by zero
In the second and fourth examples an exception was raised, terminating execution with a partial solution. Note that no exception is raised by the following:
*Main> take 13 (map (\x -> 7 / x) [10,9..])
[0.7,0.77..,0.875,1.0,1.16..,1.4,1.75,2.33..,
 3.5,7.0,Infinity,-7.0,-3.5]
This can be made to happen with div as well. The first attempt, divBy1, is not efficient since all results must be known and stored someplace just in case there is no Nothing to output (then the results are returned - otherwise Nothing is). Sample outputs are:
*Main> divBy1 7 [1,2,3,4,5]
Just [7,3,2,1,1]

*Main> divBy1 7 [1,2,3,4,0,5,6,7]
Nothing

*Main> divBy1 7 [10,9..]
Nothing
So, it's either all or nothing but it is preferred to have all the results with the Nothing occupying places where the divide-by-zero error occurs. The type signature for divBy1 is this:
divBy1 :: a -> [a] -> Maybe [a] 
but what is really required is what divBy2 provides:
divBy2 :: a -> [a] -> [Maybe a]
Sample output is this:
*Main> divBy2 7 [1,2,3,4,5]
[Just 7,Just 3,Just 2,Just 1,Just 1]

*Main> divBy2 7 [1,2,3,4,0,5,6,7]
[Just 7,Just 3,Just 2,Just 1,Nothing,
 Just 1,Just 1,Just 1]

*Main> take 13 $ divBy2 7 [10,9..]
[Just 0,Just 0,Just 0,Just 1,Just 1,Just 1,Just 1,
 Just 2,Just 3,Just 7,Nothing,Just (-7),Just (-4)]
A problem with Maybe Monad is that failure results in Nothing. That means no information is given about the failure. The Either Monad can be used to return such information. This is shown by divBy3 which has a type signature:
divBy3 :: Integral t => t -> [t] -> Either [Char] [t]
Sample out is as follows:
*Main> divBy3 7 [1,2,3,4,5]
Right [7,3,2,1,1]

*Main> divBy3 7 [1,2,3,4,0,5,6,7]
Left "divBy3: division by 0 - no good"

*Main> divBy3 7 [10,9..]
Left "divBy3: division by 0 - no good"
The counterpart to divBy2 is divBy4 with type signature
divBy4 :: Integral a => a -> [a] -> [Either a [Char]]
Sample output is as follows:
*Main> divBy4 7 [1,2,3,4,5]
[Left 7,Left 3,Left 2,Left 1,Left 1]

*Main> divBy4 7 [1,2,3,4,0,5,6,7]
[Left 7,Left 3,Left 2,Left 1,Right "Hah!!",
 Left 1,Left 1,Left 1]

*Main> take 13 $ divBy4 7 [12,11..]
[Left 0,Left 0,Left 0,Left 0,Left 0,Left 1,
 Left 1,Left 1,Left 1,Left 2,Left 3,Left 7,
 Right "Hah!!"]