You are on page 1of 101

Explicitly Typed Exceptions

for Haskell (2011?)
José Iborra
Universidad Politécnica de Valencia

PADL 2010

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

• Compare this code in a programming language:
public static void main(String[] args) {
String filepath = args[1];
Reader f = new FileReader(filepath);
doSomethingWith(f);
}

• with the equivalent Haskell code
main = do
filepath <- liftM head getArgs
contents <- readFile filepath
doSomethingWith contents

• Both can fail with an exception
• but only one compiler detects it

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

• Compare this code in a programming language:
public static void main(String[] args) {
String filepath = args[1];
Reader f = new FileReader(filepath);
doSomethingWith(f);
}

• with the equivalent Haskell code
main = do
filepath <- liftM head getArgs
contents <- readFile filepath
doSomethingWith contents

• Both can fail with an exception
• but only one compiler detects it
Main.xxxx:10: unreported exception xxxx.io.FileNotFoundException;
must be caught or declared to be thrown
Reader f = new FileReader(filepath);
^
1 error

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Checked Exceptions

• Detected and enforced by the compiler

• Usually explicit: possible exceptions appear on the type

• automatically documented

• the programmer has no need to think “what
exceptions can be raised inside this block ?”

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Checked Exceptions

• Detected and enforced by the compiler

• Usually explicit: possible exceptions appear on the type

• automatically documented

• the programmer has no need to think “what
exceptions can be raised inside this block ?”

• Checked exceptions are not always a good
thing™

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

To check or not to check ?

“I used to think that checked exceptions were really
great” - Bruce Eckel*

“I completely agree that checked exceptions
are a wonderful feature. It’s just that existing
implementations are not”
Anders Heljsberg*

* - http://www.artima.com/intv/handcuffs.html

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Exceptions in Haskell

Extensible Hierarchical Explicit Checked Traced

Haskell 98 (IO) Limited
GHC*(IO) Yes Yes
Either/ErrorT Yes Yes
but not Yes Yes but wrong
monad composable semantics

EM
Yes Yes Yes Yes Yes!
monad

GHC* - An extensible dynamically typed hierarchy of Exceptions - S. Marlow (2006)

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Error handling in Haskell

data Expr = Add Expr Expr | Div Expr Expr | Val Double

eval :: Expr -> Double
eval (Val x) = x
eval (Add e1 e2) = eval e1 + eval e2
eval (Div e1 e2) = eval e1 / eval e2

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Error handling in Haskell

data Expr = Add Expr Expr | Div Expr Expr | Val Double

eval :: Expr -> Double
eval (Val x) = x
eval (Add e1 e2) = eval e1 + eval e2
eval (Div e1 e2) = case eval e2 of
0 -> exception !
x2 -> eval e1 / x2

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Error handling in Haskell
data Either a b = Left a | Right b

data Expr = Add Expr Expr | Div Expr Expr | Val Double

eval :: Expr -> Either exception Double
eval (Val x) = x
eval (Add e1 e2) = eval e1 + eval e2
eval (Div e1 e2) = case eval e2 of
0 -> Left exception
x2 -> Right (eval e1 / x2)

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Error handling in Haskell
data Either a b = Left a | Right b

data Expr = Add Expr Expr | Div Expr Expr | Val Double
data DivByZero = DivByZero deriving Show

eval :: Expr -> Either DivByZero Double
eval (Val x) = x
eval (Add e1 e2) = eval e1 + eval e2
eval (Div e1 e2) = case eval e2 of
0 -> Left DivByZero
x2 -> Right (eval e1 / x2)

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Error handling in Haskell
data Either a b = Left a | Right b

data Expr = Add Expr Expr | Div Expr Expr | Val Double
data DivByZero = DivByZero deriving Show

eval :: Expr -> Either DivByZero Double
eval (Val x) = x
eval (Add e1 e2) = eval e1 + eval e2
eval (Div e1 e2) = case eval e2 of
0 -> Left DivByZero
x2 -> Right (eval e1 / x2)

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Error handling in Haskell
data Either a b = Left a | Right b

data Expr = Add Expr Expr | Div Expr Expr | Val Double
data DivByZero = DivByZero deriving Show

eval :: Expr -> Either DivByZero Double
eval (Val x) = Right x
eval (Add e1 e2) = eval e1 + eval e2
eval (Div e1 e2) = case eval e2 of
0 -> Left DivByZero
x2 -> Right (eval e1 / x2)

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Error handling in Haskell
data Either a b = Left a | Right b

data Expr = Add Expr Expr | Div Expr Expr | Val Double
data DivByZero = DivByZero deriving Show

eval :: Expr -> Either DivByZero Double
eval (Val x) = Right x
eval (Add e1 e2) = case eval e1 of
Right x1 -> case eval e2 of
Right x2 -> Right(x1 + x2)
eval (Div e1 e2) = case eval e2 of
0 -> Left DivByZero
x2 -> Right (eval e1 / x2)

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Error handling in Haskell
data Either a b = Left a | Right b

data Expr = Add Expr Expr | Div Expr Expr | Val Double
data DivByZero = DivByZero deriving Show

eval :: Expr -> Either DivByZero Double
eval (Val x) = Right x
eval (Add e1 e2) = case eval e1 of
Right x1 -> case eval e2 of
Right x2 -> Right(x1 + x2)
eval (Div e1 e2) = case eval e2 of
Right 0 -> Left DivByZero
Right x2 -> Right (eval e1 / x2)

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Error handling in Haskell
data Either a b = Left a | Right b

data Expr = Add Expr Expr | Div Expr Expr | Val Double
data DivByZero = DivByZero deriving Show

eval :: Expr -> Either DivByZero Double
eval (Val x) = Right x
eval (Add e1 e2) = case eval e1 of
Right x1 -> case eval e2 of
Right x2 -> Right(x1 + x2)
eval (Div e1 e2) = case eval e2 of
Right 0 -> Left DivByZero
Right x2 -> case eval e1 of
Right x1 -> Right(x1 / x2)

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Error handling in Haskell
data Either a b = Left a | Right b

data Expr = Add Expr Expr | Div Expr Expr | Val Double
data DivByZero = DivByZero deriving Show

eval :: Expr -> Either DivByZero Double
eval (Val x) = Right x
eval (Add e1 e2) = case eval e1 of
Left e -> Left e
Right x1 -> case eval e2 of
Right x2 -> Right(x1 + x2)
eval (Div e1 e2) = case eval e2 of
Right 0 -> Left DivByZero
Right x2 -> case eval e1 of
Right x1 -> Right(x1 / x2)

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Error handling in Haskell
data Either a b = Left a | Right b

data Expr = Add Expr Expr | Div Expr Expr | Val Double
data DivByZero = DivByZero deriving Show

eval :: Expr -> Either DivByZero Double
eval (Val x) = Right x
eval (Add e1 e2) = case eval e1 of
Left e -> Left e
Right x1 -> case eval e2 of
Left e -> Left e
Right x2 -> Right(x1 + x2)
eval (Div e1 e2) = case eval e2 of
Right 0 -> Left DivByZero
Right x2 -> case eval e1 of
Right x1 -> Right(x1 / x2)

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Error handling in Haskell
data Either a b = Left a | Right b

data Expr = Add Expr Expr | Div Expr Expr | Val Double
data DivByZero = DivByZero deriving Show

eval :: Expr -> Either DivByZero Double
eval (Val x) = Right x
eval (Add e1 e2) = case eval e1 of
Left e -> Left e
Right x1 -> case eval e2 of
Left e -> Left e
Right x2 -> Right(x1 + x2)
eval (Div e1 e2) = case eval e2 of
Left e -> Left e
Right 0 -> Left DivByZero
Right x2 -> case eval e1 of
Right x1 -> Right(x1 / x2)

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Error handling in Haskell
data Either a b = Left a | Right b

data Expr = Add Expr Expr | Div Expr Expr | Val Double
data DivByZero = DivByZero deriving Show

eval :: Expr -> Either DivByZero Double
eval (Val x) = Right x
eval (Add e1 e2) = case eval e1 of
Left e -> Left e
Right x1 -> case eval e2 of
Left e -> Left e
Right x2 -> Right(x1 + x2)
eval (Div e1 e2) = case eval e2 of
Left e -> Left e
Right 0 -> Left DivByZero
Right x2 -> case eval e1 of
Left e -> Left e
Right x1 -> Right(x1 / x2)

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Error handling in Haskell
data Expr = Add Expr Expr | Div Expr Expr | Val Double
data DivByZero = DivByZero deriving Show

eval :: Expr -> Either DivByZero Double
eval (Val x) = Right x
eval (Add e1 e2) = case eval e1 of
Left e -> Left e
Right x1 -> case eval e2 of
Left e -> Left e
Right x2 -> Right(x1 + x2)
eval (Div e1 e2) = case eval e2 of
Left e -> Left e
Right 0 -> Left DivByZero
Right x2 -> case eval e1 of
Left e -> Left e
Right x1 -> Right(x1 / x2)

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Error handling with monads
data Expr = Add Expr Expr | Div Expr Expr | Val Double
data DivByZero = DivByZero deriving Show

eval :: Expr -> Either DivByZero Double
eval (Val x) = Right x
eval (Add e1 e2) = case eval e1 of
Left e -> Left e
Right x1 -> case eval e2 of
Left e -> Left e
Right x2 -> Right(x1 + x2)
eval (Div e1 e2) = case eval e2 of
Left e -> Left e
Right 0 -> Left DivByZero
Right x2 -> case eval e1 of
Left e -> Left e
Right x1 -> Right(x1 / x2)

Left e >>= f = Left e
Right x >>= f = f x

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Error handling with monads
data Expr = Add Expr Expr | Div Expr Expr | Val Double
data DivByZero = DivByZero deriving Show

eval :: Expr -> Either DivByZero Double
eval (Val x) = Right x
eval (Add e1 e2) = e1 >>= \x1 -> case eval e2 of
Left e -> Left e
Right x2 -> Right(x1 + x2)
eval (Div e1 e2) = case eval e2 of
Left e -> Left e
Right 0 -> Left DivByZero
Right x2 -> case eval e1 of
Left e -> Left e
Right x1 -> Right(x1 / x2)

Left e >>= f = Left e
Right x >>= f = f x

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Error handling with monads
data Expr = Add Expr Expr | Div Expr Expr | Val Double
data DivByZero = DivByZero deriving Show

eval :: Expr -> Either DivByZero Double
eval (Val x) = Right x
eval (Add e1 e2) = eval e1 >>= \x1 -> eval e2 >>= \x2 ->
Right(x1 + x2)
eval (Div e1 e2) = case eval e2 of
Left e -> Left e
Right 0 -> Left DivByZero
Right x2 -> case eval e1 of
Left e -> Left e
Right x1 -> Right(x1 / x2)

Left e >>= f = Left e
Right x >>= f = f x

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Error handling with monads
data Expr = Add Expr Expr | Div Expr Expr | Val Double
data DivByZero = DivByZero deriving Show

eval :: Expr -> Either DivByZero Double
eval (Val x) = Right x
eval (Add e1 e2) = eval e1 >>= \x1 -> eval e2 >>= \x2 ->
Right(x1 + x2)
eval (Div e1 e2) = eval e2 >>= \x2 ->
case x2 of
0 -> Left DivByZero
x2 -> case eval e1 of
Left e -> Left e
Right x1 -> Right(x1 / x2)

Left e >>= f = Left e
Right x >>= f = f x

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Error handling with monads
data Expr = Add Expr Expr | Div Expr Expr | Val Double
data DivByZero = DivByZero deriving Show

eval :: Expr -> Either DivByZero Double
eval (Val x) = Right x
eval (Add e1 e2) = eval e1 >>= \x1 -> eval e2 >>= \x2 ->
Right(x1 + x2)
eval (Div e1 e2) = eval e2 >>= \x2 ->
case x2 of
0 -> Left DivByZero
x2 -> eval e1 >>= \x1 -> Right(x1 / x2)

Left e >>= f = Left e
Right x >>= f = f x

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Error handling with monads
data Expr = Add Expr Expr | Div Expr Expr | Val Double
data DivByZero = DivByZero deriving Show

eval :: Expr -> Either DivByZero Double
eval (Val x) = Right x
eval (Add e1 e2) = eval e1 >>= \x1 -> eval e2 >>= \x2 ->
Right(x1 + x2)
eval (Div e1 e2) = eval e2 >>= \x2 ->
case x2 of
0 -> Left DivByZero
x2 -> eval e1 >>= \x1 -> Right(x1 / x2)

instance Error e => Monad (Either e) where
Left e >>= f = Left e
Right x >>= f = f x

return = Right

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Error handling with monads
data Expr = Add Expr Expr | Div Expr Expr | Val Double
data DivByZero = DivByZero deriving Show

eval :: Expr -> Either DivByZero Double
eval (Val x) = return x
eval (Add e1 e2) = eval e1 >>= \x1 -> eval e2 >>= \x2 ->
Right(x1 + x2)
eval (Div e1 e2) = eval e2 >>= \x2 ->
case x2 of
0 -> Left DivByZero
x2 -> eval e1 >>= \x1 -> Right(x1 / x2)

instance Error e => Monad (Either e) where
Left e >>= f = Left e
Right x >>= f = f x

return = Right

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Error handling with monads
data Expr = Add Expr Expr | Div Expr Expr | Val Double
data DivByZero = DivByZero deriving Show

eval :: Expr -> Either DivByZero Double
eval (Val x) = return x
eval (Add e1 e2) = eval e1 >>= \x1 -> eval e2 >>= \x2 ->
return(x1 + x2)
eval (Div e1 e2) = eval e2 >>= \x2 ->
case x2 of
0 -> Left DivByZero
x2 -> eval e1 >>= \x1 -> Right(x1 / x2)

instance Error e => Monad (Either e) where
Left e >>= f = Left e
Right x >>= f = f x

return = Right

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Error handling with monads
data Expr = Add Expr Expr | Div Expr Expr | Val Double
data DivByZero = DivByZero deriving Show

eval :: Expr -> Either DivByZero Double
eval (Val x) = return x
eval (Add e1 e2) = eval e1 >>= \x1 -> eval e2 >>= \x2 ->
return(x1 + x2)
eval (Div e1 e2) = eval e2 >>= \x2 ->
case x2 of
0 -> Left DivByZero
x2 -> eval e1 >>= \x1 -> return(x1 / x2)

instance Error e => Monad (Either e) where
Left e >>= f = Left e
Right x >>= f = f x

return = Right

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Error handling with monads
data Expr = Add Expr Expr | Div Expr Expr | Val Double
data DivByZero = DivByZero deriving Show

eval :: Expr -> Either DivByZero Double
eval (Val x) = return x
eval (Add e1 e2) = do x1 <- eval e1
x2 <- eval e2
return (x1 + x2)
eval (Div e1 e2) = eval e2 >>= \x2 ->
case x2 of
0 -> Left DivByZero
x2 -> eval e1 >>= \x1 -> return(x1 / x2)

instance Error e => Monad (Either e) where
Left e >>= f = Left e
Right x >>= f = f x

return = Right

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Error handling with monads
data Expr = Add Expr Expr | Div Expr Expr | Val Double
data DivByZero = DivByZero deriving Show

eval :: Expr -> Either DivByZero Double
eval (Val x) = return x
eval (Add e1 e2) = do x1 <- eval e1
x2 <- eval e2
return (x1 + x2)
eval (Div e1 e2) = do x1 <- eval e1
x2 <- eval e2
case x2 of
0 -> Left DivByZero
x2 -> return (x1 / x2)

instance Error e => Monad (Either e) where
Left e >>= f = Left e
Right x >>= f = f x

return = Right

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Error handling with monads
data Expr = Add Expr Expr | Div Expr Expr | Val Double
data DivByZero = DivByZero deriving Show

eval :: Expr -> Either DivByZero Double
eval (Val x) = return x
eval (Add e1 e2) = do x1 <- eval e1
x2 <- eval e2
return (x1 + x2)
eval (Div e1 e2) = do x1 <- eval e1
x2 <- eval e2
case x2 of
0 -> throw DivByZero
x2 -> return (x1 / x2)

throw = Left

instance Error e => Monad (Either e) where
Left e >>= f = Left e
Right x >>= f = f x

return = Right
José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Error handling with monads
data Expr = Add Expr Expr | Div Expr Expr | Val Double
data DivByZero = DivByZero deriving Show

eval :: Expr -> Either DivByZero Double
eval (Val x) = return x
eval (Add e1 e2) = do x1 <- eval e1
x2 <- eval e2
return (x1 + x2)
eval (Div e1 e2) = do x1 <- eval e1
x2 <- eval e2
case x2 of
0 -> throw DivByZero
x2 -> return (x1 / x2)

throw = Left

catch (Right x) handler = Right x
catch (Left e) handler = handler e

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

• User extensible

The Either Monad • Hierarchical

• Checked

• Explicit
data Expr = Add Expr Expr | Div Expr Expr | Val Double
data DivByZero = DivByZero deriving Show

eval :: Expr -> Either DivByZero Double
eval (Val x) = return x
eval (Add e1 e2) = do x1 <- eval e1
x2 <- eval e2
return (x1 + x2)
eval (Div e1 e2) = do x1 <- eval e1
x2 <- eval e2
case x2 of
0 -> throw DivByZero
x2 -> return (x1 / x2)

throw = Left

catch (Right x) handler = Right x
catch (Left e) handler = handler e

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

• User extensible

The Either Monad

• Hierarchical

• Checked

• Explicit
data Expr = Add Expr Expr | Div Expr Expr | Val Double
data DivByZero = DivByZero deriving Show

eval :: Expr -> Either DivByZero Double
eval (Val x) = return x
eval (Add e1 e2) = do x1 <- eval e1
x2 <- eval e2
return (x1 + x2)
eval (Div e1 e2) = do x1 <- eval e1
x2 <- eval e2
case x2 of
0 -> throw DivByZero
x2 -> return (x1 / x2)

throw = Left

parse :: String -> Either ParseError Expr

run :: String -> Either ??? Double
run str = do { e <- parse str; eval e }

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

• User extensible

The Either Monad

• Hierarchical

• Checked

• Explicit
data Expr = Add Expr Expr | Div Expr Expr | Val Double
data DivByZero = DivByZero deriving Show

eval :: Expr -> Either DivByZero Double
parse :: String -> Either ParseError Expr

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

• User extensible

The Either Monad

• Hierarchical

• Checked

• Explicit
data Expr = Add Expr Expr | Div Expr Expr | Val Double
data DivByZero = DivByZero deriving Show

eval :: Expr -> Either DivByZero Double
parse :: String -> Either ParseError Expr

data ParseOrDivError = ParseE ParseError
| EvalE DivByZero

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

• User extensible

The Either Monad

• Hierarchical

• Checked

• Explicit
data Expr = Add Expr Expr | Div Expr Expr | Val Double
data DivByZero = DivByZero deriving Show

eval :: Expr -> Either DivByZero Double
parse :: String -> Either ParseError Expr

data ParseOrDivError = ParseE ParseError
| EvalE DivByZero

mapError :: (e -> e’) -> Either e a -> Either e’ a
mapError f (Left e) = Left (f e)
mapError f (Right r) = Right r

parse’ = mapError ParseE . parse
eval’ = mapError EvalE . eval

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

• User extensible

The Either Monad

• Hierarchical

• Checked

• Explicit
data Expr = Add Expr Expr | Div Expr Expr | Val Double
data DivByZero = DivByZero deriving Show

eval :: Expr -> Either DivByZero Double
parse :: String -> Either ParseError Expr

data ParseOrDivError = ParseE ParseError
| EvalE DivByZero

mapError :: (e -> e’) -> Either e a -> Either e’ a
mapError f (Left e) = Left (f e)
mapError f (Right r) = Right r

parse’ = mapError ParseE . parse
eval’ = mapError EvalE . eval

run :: String -> Either ParseOrDivError Double
run str = do { e <- parse’ str; eval’ e }

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

• User extensible

The Either Monad

• Hierarchical ✓
• Checked

• Explicit
data Expr = Add Expr Expr | Div Expr Expr | Val Double
data DivByZero = DivByZero deriving Show

eval :: Expr -> Either DivByZero Double
parse :: String -> Either ParseError Expr

data ParseOrDivError = ParseE ParseError
| EvalE DivByZero

mapError :: (e -> e’) -> Either e a -> Either e’ a
mapError f (Left e) = Left (f e)
mapError f (Right r) = Right r

parse’ = mapError ParseE . parse
eval’ = mapError EvalE . eval

run :: String -> Either ParseOrDivError Double
run str = do { e <- parse’ str; eval’ e }

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

• User extensible

The Either Monad

• Hierarchical ✓
• Checked ✘
• Explicit
data Expr = Add Expr Expr | Div Expr Expr | Val Double
data DivByZero = DivByZero deriving Show

eval :: Expr -> Either DivByZero Double
parse :: String -> Either ParseError Expr

data ParseOrDivError = ParseE ParseError
| EvalE DivByZero

mapError :: (e -> e’) -> Either e a -> Either e’ a
mapError f (Left e) = Left (f e)
mapError f (Right r) = Right r

parse’ = mapError ParseE . parse
eval’ = mapError EvalE . eval

run :: String -> Either ParseOrDivError Double
run str = do { e <- parse’ str; eval’ e }

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

• User extensible

The Either Monad

• Hierarchical ✓
• Checked ✘
• Explicit
data Expr = Add Expr Expr | Div Expr Expr | Val Double
data DivByZero = DivByZero deriving Show

eval :: Expr -> Either DivByZero Double
parse :: String -> Either ParseError Expr

data ParseOrDivError = ParseE ParseError
| EvalE DivByZero

run :: String -> Either ParseOrDivError Double
run str = do { e <- parse’ str; eval’ e }

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

• User extensible

The Either Monad

• Hierarchical ✓
• Checked

• Explicit
data Expr = Add Expr Expr | Div Expr Expr | Val Double
data DivByZero = DivByZero deriving Show

eval :: Expr -> Either DivByZero Double
parse :: String -> Either ParseError Expr

data ParseOrDivError = ParseE ParseError
| EvalE DivByZero

run :: String -> Either ParseOrDivError Double
run str = do
e <- parse’ str
eval’ e

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

• User extensible

The Either Monad

• Hierarchical ✓
• Checked

• Explicit
data Expr = Add Expr Expr | Div Expr Expr | Val Double
data DivByZero = DivByZero deriving Show

eval :: Expr -> Either DivByZero Double
parse :: String -> Either ParseError Expr

data ParseOrDivError = ParseE ParseError
| EvalE DivByZero

run :: String -> Either ParseOrDivError Double
run str = do
e <- parse’ str
eval’ e `catch` \EvalE DivByZero -> return 0

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

• User extensible

The Either Monad

• Hierarchical ✓
• Checked

• Explicit
data Expr = Add Expr Expr | Div Expr Expr | Val Double
data DivByZero = DivByZero deriving Show

eval :: Expr -> Either DivByZero Double
parse :: String -> Either ParseError Expr

data ParseOrDivError = ParseE ParseError
| EvalE DivByZero

run :: String -> Either ParseOrDivError Double
run str = do
e <- parse’ str
eval’ e `catch` \EvalE DivByZero -> return 0

Warning: Pattern match(es) are non-exhaustive
In a case alternative:
Patterns not matched:
ParseE

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

• User extensible

The Either Monad

• Hierarchical ✓
• Checked

• Explicit ✓
data Expr = Add Expr Expr | Div Expr Expr | Val Double
data DivByZero = DivByZero deriving Show

eval :: Expr -> Either DivByZero Double
parse :: String -> Either ParseError Expr

data ParseOrDivError = ParseE ParseError
| EvalE DivByZero

run :: String -> Either ParseOrDivError Double
run str = do
e <- parse’ str
eval’ e `catch` \EvalE DivByZero -> return 0

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

A monad for Explicitly Typed Exceptions

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Fixing the composability problem

* An extensible dynamically typed hierarchy of Exceptions - S. Marlow (2006)
José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Fixing the composability problem

• Apply the extensible + hierarchical exceptions datatype of
Marlow*

* An extensible dynamically typed hierarchy of Exceptions - S. Marlow (2006)
José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Fixing the composability problem

• Apply the extensible + hierarchical exceptions datatype of
Marlow*
data SomeException = ∀ e. (Show e, Typeable e) => SomeException e

class Exception e where

* An extensible dynamically typed hierarchy of Exceptions - S. Marlow (2006)
José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Fixing the composability problem

• Apply the extensible + hierarchical exceptions datatype of
Marlow*
data SomeException = ∀ e. (Show e, Typeable e) => SomeException e

class Exception e where
fromException :: SomeException -> e
toException :: e -> SomeException

* An extensible dynamically typed hierarchy of Exceptions - S. Marlow (2006)
José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Fixing the composability problem

• Apply the extensible + hierarchical exceptions datatype of
Marlow*
data SomeException = ∀ e. (Show e, Typeable e) => SomeException e

class Exception e where
fromException :: SomeException -> e
toException :: e -> SomeException

• defining a new monad of non-explicit, composable
exceptions

* An extensible dynamically typed hierarchy of Exceptions - S. Marlow (2006)
José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Fixing the composability problem

• Apply the extensible + hierarchical exceptions datatype of
Marlow*
data SomeException = ∀ e. (Show e, Typeable e) => SomeException e

class Exception e where
fromException :: SomeException -> e
toException :: e -> SomeException

• defining a new monad of non-explicit, composable
exceptions
newtype C# a = C# (Either SomeException a)
deriving Monad -- C# is isomorphic to Either

throwC# :: Exception e => e -> C# a

* An extensible dynamically typed hierarchy of Exceptions - S. Marlow (2006)
José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Fixing the composability problem

• Apply the extensible + hierarchical exceptions datatype of
Marlow*
data SomeException = ∀ e. (Show e, Typeable e) => SomeException e

class Exception e where
fromException :: SomeException -> e
toException :: e -> SomeException

• defining a new monad of non-explicit, composable
exceptions
newtype C# a = C# (Either SomeException a)
deriving Monad -- C# is isomorphic to Either

throwC# :: Exception e => e -> C# a
throwC# = C# . Left . toException

* An extensible dynamically typed hierarchy of Exceptions - S. Marlow (2006)
José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Fixing the composability problem

• Apply the extensible + hierarchical exceptions datatype of
Marlow*
data SomeException = ∀ e. (Show e, Typeable e) => SomeException e

class Exception e where
fromException :: SomeException -> e
toException :: e -> SomeException

• defining a new monad of non-explicit, composable
exceptions
newtype C# a = C# (Either SomeException a)
deriving Monad -- C# is isomorphic to Either

throwC# :: Exception e => e -> C# a
throwC# = C# . Left . toException

* An extensible dynamically typed hierarchy of Exceptions - S. Marlow (2006)
José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Fixing the composability problem

• Apply the extensible + hierarchical exceptions datatype of
Marlow*
data SomeException = ∀ e. (Show e, Typeable e) => SomeException e

class Exception e where
fromException :: SomeException -> e
toException :: e -> SomeException

• defining a new monad of non-explicit, composable
exceptions
newtype C# a = C# (Either SomeException a)
deriving Monad -- C# is isomorphic to Either

throwC# :: Exception e => e -> C# a
throwC# = C# . Left . toException

catchC# = ... -- uses casting, slightly more involved

* An extensible dynamically typed hierarchy of Exceptions - S. Marlow (2006)
José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Fixing the composability problem

• Apply the extensible + hierarchical exceptions datatype of
Marlow*
data SomeException = ∀ e. (Show e, Typeable e) => SomeException e

class Exception e where
fromException :: SomeException -> e
toException :: e -> SomeException

• defining a new monad of non-explicit, composable
exceptions
newtype C# a = C# (Either SomeException a)
deriving Monad -- C# is isomorphic to Either
• User extensible

throwC# :: Exception e => e -> C# a
• Hierarchical

throwC# = C# . Left . toException
• Checked

• Explicit

catchC# = ... -- uses casting, slightly more involved

* An extensible dynamically typed hierarchy of Exceptions - S. Marlow (2006)
José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Fixing the composability problem

• Apply the extensible + hierarchical exceptions datatype of
Marlow*
data SomeException = ∀ e. (Show e, Typeable e) => SomeException e

class Exception e where
fromException :: SomeException -> e
toException :: e -> SomeException

• defining a new monad of non-explicit, composable
exceptions
newtype C# a = C# (Either SomeException a)
deriving Monad -- C# is isomorphic to Either
• User extensible ✓

throwC# :: Exception e => e -> C# a
• Hierarchical

throwC# = C# . Left . toException
• Checked

• Explicit

catchC# = ... -- uses casting, slightly more involved

* An extensible dynamically typed hierarchy of Exceptions - S. Marlow (2006)
José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Fixing the composability problem

• Apply the extensible + hierarchical exceptions datatype of
Marlow*
data SomeException = ∀ e. (Show e, Typeable e) => SomeException e

class Exception e where
fromException :: SomeException -> e
toException :: e -> SomeException

• defining a new monad of non-explicit, composable
exceptions
newtype C# a = C# (Either SomeException a)
deriving Monad -- C# is isomorphic to Either
• User extensible ✓

throwC# :: Exception e => e -> C# a
• Hierarchical ✓

throwC# = C# . Left . toException
• Checked

• Explicit

catchC# = ... -- uses casting, slightly more involved

* An extensible dynamically typed hierarchy of Exceptions - S. Marlow (2006)
José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Fixing the composability problem

• Apply the extensible + hierarchical exceptions datatype of
Marlow*
data SomeException = ∀ e. (Show e, Typeable e) => SomeException e

class Exception e where
fromException :: SomeException -> e
toException :: e -> SomeException

• defining a new monad of non-explicit, composable
exceptions
newtype C# a = C# (Either SomeException a)
deriving Monad -- C# is isomorphic to Either
• User extensible ✓

throwC# :: Exception e => e -> C# a
• Hierarchical ✓

throwC# = C# . Left . toException
• Checked ✘
• Explicit

catchC# = ... -- uses casting, slightly more involved

* An extensible dynamically typed hierarchy of Exceptions - S. Marlow (2006)
José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Fixing the composability problem

• Apply the extensible + hierarchical exceptions datatype of
Marlow*
data SomeException = ∀ e. (Show e, Typeable e) => SomeException e

class Exception e where
fromException :: SomeException -> e
toException :: e -> SomeException

• defining a new monad of non-explicit, composable
exceptions
newtype C# a = C# (Either SomeException a)
deriving Monad -- C# is isomorphic to Either
• User extensible ✓

throwC# :: Exception e => e -> C# a
• Hierarchical ✓

throwC# = C# . Left . toException
• Checked ✘
• Explicit ✘
catchC# = ... -- uses casting, slightly more involved

* An extensible dynamically typed hierarchy of Exceptions - S. Marlow (2006)
José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

data Expr = Add Expr Expr | Div Expr Expr | Val Double
data DivByZero = DivByZero deriving (Show,Typeable)
instance Exception DivByZero

eval :: Expr -> C# Double
eval (Val x) = return x
eval (Add e1 e2) = do x1 <- eval e1
x2 <- eval e2
return (x1 / x2)
eval (Div e1 e2) = do x1 <- eval e1
x2 <- eval e2
case x2 of
0 -> throwC# DivByZero
x2 -> return (x1 / x2)

parse :: String -> C# Expr

run :: String -> C# Double
run str = do { e <- parse str; eval e }

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

The Explicit Exceptions Monad

newtype EM l a = EM (Either SomeException a) deriving Monad

class Exception e => Throws e l

throwEM :: Throws e l => e -> EM l a
throwEM = EM . Left . toException

* An extensible dynamically typed hierarchy of Exceptions - S. Marlow (2006)
José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

The Explicit Exceptions Monad
• Idea: the type of a computation includes the exceptions it
may throw.

newtype EM l a = EM (Either SomeException a) deriving Monad

class Exception e => Throws e l

throwEM :: Throws e l => e -> EM l a
throwEM = EM . Left . toException

* An extensible dynamically typed hierarchy of Exceptions - S. Marlow (2006)
José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

The Explicit Exceptions Monad
• Idea: the type of a computation includes the exceptions it
may throw.

• Establish a type-level relationship between a computation
and every exception it may throw

• Encoded as a list of type class constraints

newtype EM l a = EM (Either SomeException a) deriving Monad

class Exception e => Throws e l

throwEM :: Throws e l => e -> EM l a
throwEM = EM . Left . toException

* An extensible dynamically typed hierarchy of Exceptions - S. Marlow (2006)
José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

The Explicit Exceptions Monad
• Idea: the type of a computation includes the exceptions it
may throw.

• Establish a type-level relationship between a computation
and every exception it may throw

• Encoded as a list of type class constraints

newtype EM l a = EM (Either SomeException a) deriving Monad

class Exception e => Throws e l This is not the most
general type
throwEM :: Throws e l => e -> EM l a
throwEM = EM . Left . toException

* An extensible dynamically typed hierarchy of Exceptions - S. Marlow (2006)
José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

data Expr = Add Expr Expr | Div Expr Expr | Val Double
data DivByZero = DivByZero deriving (Show,Typeable)
instance Exception DivByZero

eval :: Throws DivByZero l => Expr -> EM l Double
eval (Val x) = return x
eval (Add e1 e2) = do x1 <- eval e1
x2 <- eval e2
return (x1 / x2)
eval (Div e1 e2) = do x1 <- eval e1
x2 <- eval e2
case x2 of
0 -> throwEM DivByZero
x2 -> return (x1 / x2)

parse :: Throws ParseError l => String -> EM l Expr

run :: (Throws DivByZero l, Throws ParseError l) =>
String -> EM l Double
run str = do { e <- parse str; eval e }

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

The Explicit Exceptions Monad Kernel
(a la Lightweight Dependent Types)*

newtype EM l a = EM (Either SomeException a) deriving Monad
private
public
EM a >>=EM k = EM (a >>=Either ...)
returnEM = EM . returnEither

throwEM :: Throws e l => e -> EM l a
throwEM = EM . Left . toException --identical to throwC#, modulo the EM wrapper

catchEM :: Exception e => EM (Caught e l) a -> (e -> EM l a) -> EM l a
catchEM = ... -- identical to catchC#, modulo the EM wrapper

runEM :: EM l x -> x
runEM (EM (Right x)) = x

tryEM :: EM Any x -> Either SomeException x
tryEM (EM x) = x

* - Lightweight static capabilities, Kiselyov & Shan, 2007
José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Reasoning about exceptions
M, N = return H H ∈ pure
| M >>= N
| throw e
| catch M (λe → N )
| if H then M else N

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Reasoning about exceptions
M, N = return H H ∈ pure
| M >>= N
| throw e
| catch M (λe → N )
| if H then M else N

|return H| = {} |M | = e2 |throw e| = {e}

|M | = m |N | = n |M | = m |N | = n
|M >>= N | = m ∪ n |if H then M else N | = m ∪ n

|C| = c |H| = h
|catch C (λe → H)| = (c \ {e}) ∪ h

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Reasoning about exceptions
M, N = return H H ∈ pure
| M >>= N
| throw e
| catch M (λe → N )
| if H then M else N

|return H| = {} |M | = e2 |throw e| = {e}

|M | = m |N | = n |M | = m |N | = n
|M >>= N | = m ∪ n |if H then M else N | = m ∪ n
>>=EM :: EM l a -> (a -> EM l b) -> EM l b
|C| = c |H| = h
|catch C (λe → H)| = (c \ {e}) ∪ h

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Reasoning about exceptions
M, N = return H H ∈ pure
| M >>= N
| throw e
| catch M (λe → N )
| if H then M else N

|return H| = {} |M | = e2 |throw e| = {e}

|M | = m |N | = n |M | = m |N | = n
|M >>= N | = m ∪ n |if H then M else N | = m ∪ n

|C| = c |H| = h
|catch C (λe → H)| = (c \ {e}) ∪ h

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Implementing Catch
|C| = c |H| = h
|catch C (λe → H)| = (c \ {e}) ∪ h

catch :: Exception e => EM (Caught e l) a -> (e -> EM l a) -> EM l a
catch = ... --omitted, as before

data Caught e l
instance Throws e (Caught e l)
instance Throws e l => Throws e (Caught e1 l)

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Implementing Catch
|C| = c |H| = h
|catch C (λe → H)| = (c \ {e}) ∪ h

catch :: Exception e => EM (Caught e l) a -> (e -> EM l a) -> EM l a
catch = ... --omitted, as before

data Caught e l
This is not the most
instance Throws e (Caught e l) general type
instance Throws e l => Throws e (Caught e1 l)

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Implementing Catch
|C| = c |H| = h
|catch C (λe → H)| = (c \ {e}) ∪ h

catch :: Exception e => EM (Caught e l) a -> (e -> EM l a) -> EM l a
catch = ... --omitted, as before

data Caught e l
instance Throws e (Caught e l)
instance Throws e l => Throws e (Caught e1 l)

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Implementing Catch
|C| = c |H| = h
|catch C (λe → H)| = (c \ {e}) ∪ h

catch :: Exception e => EM (Caught e l) a -> (e -> EM l a) -> EM l a
catch = ... --omitted, as before

data Caught e l
instance Throws e (Caught e l)
instance Throws e l => Throws e (Caught e1 l)

parse :: Throws ParseError l => String -> EM l Expr
run :: ... => String -> ...
run str = do
e <- parse str `catch` \ParseError -> ...
eval e

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Implementing Catch
|C| = c |H| = h
|catch C (λe → H)| = (c \ {e}) ∪ h

catch :: Exception e => EM (Caught e l) a -> (e -> EM l a) -> EM l a
catch = ... --omitted, as before

data Caught e l
instance Throws e (Caught e l)
instance Throws e l => Throws e (Caught e1 l)

parse :: Throws ParseError l => String -> EM l Expr
run :: ... => String -> ...
run str = do
e <- parse str `catch` \ParseError -> ...
eval e

(`catch` \ParseError -> ..) :: EM (Caught ParseError l2) a -> EM l2 a

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Implementing Catch
|C| = c |H| = h
|catch C (λe → H)| = (c \ {e}) ∪ h

catch :: Exception e => EM (Caught e l) a -> (e -> EM l a) -> EM l a
catch = ... --omitted, as before

data Caught e l
instance Throws e (Caught e l)
instance Throws e l => Throws e (Caught e1 l)

parse :: Throws ParseError l => String -> EM l Expr
run :: ... => String -> ...
run str = do
e <- parse str `catch` \ParseError -> ...
eval e

(`catch` \ParseError -> ..) :: EM (Caught ParseError l2) a -> EM l2 a
parse str :: Throws ParseError l1 => EM l1 Expr

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Implementing Catch
|C| = c |H| = h
|catch C (λe → H)| = (c \ {e}) ∪ h

catch :: Exception e => EM (Caught e l) a -> (e -> EM l a) -> EM l a
catch = ... --omitted, as before

data Caught e l
instance Throws e (Caught e l)
instance Throws e l => Throws e (Caught e1 l)

parse :: Throws ParseError l => String -> EM l Expr
run :: ... => String -> ...
run str = do
e <- parse str `catch` \ParseError -> ...
eval e

(`catch` \ParseError -> ..) :: EM (Caught ParseError l2) a -> EM l2 a
parse str :: Throws ParseError l1 => EM l1 Expr
parse `catch` \ParseError... :: Throws ParseError (Caught ParseError l2) => EM l2 Expr

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Implementing Catch
|C| = c |H| = h
|catch C (λe → H)| = (c \ {e}) ∪ h

catch :: Exception e => EM (Caught e l) a -> (e -> EM l a) -> EM l a
catch = ... --omitted, as before

data Caught e l
instance Throws e (Caught e l)
instance Throws e l => Throws e (Caught e1 l)

parse :: Throws ParseError l => String -> EM l Expr
run :: ... => String -> ...
run str = do
e <- parse str `catch` \ParseError -> ...
eval e

(`catch` \ParseError -> ..) :: EM (Caught ParseError l2) a -> EM l2 a
parse str :: Throws ParseError l1 => EM l1 Expr
parse `catch` \ParseError... :: EM l2 Expr

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Implementing Catch
|C| = c |H| = h
|catch C (λe → H)| = (c \ {e}) ∪ h

catch :: Exception e => EM (Caught e l) a -> (e -> EM l a) -> EM l a
catch = ... --omitted, as before

data Caught e l
instance Throws e (Caught e l)
instance Throws e l => Throws e (Caught e1 l)

parse :: Throws ParseError l => String -> EM l Expr
run :: ... => String -> ...
run str = do
e <- parse str `catch` \ParseError -> ...
eval e

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Implementing Catch
|C| = c |H| = h
|catch C (λe → H)| = (c \ {e}) ∪ h

catch :: Exception e => EM (Caught e l) a -> (e -> EM l a) -> EM l a
catch = ... --omitted, as before

data Caught e l
instance Throws e (Caught e l)
instance Throws e l => Throws e (Caught e1 l)

parse :: Throws ParseError l => String -> EM l Expr
run :: ... => String -> ...
run str = do
e <- parse str `catch` \DivByZero -> ...
eval e

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Implementing Catch
|C| = c |H| = h
|catch C (λe → H)| = (c \ {e}) ∪ h

catch :: Exception e => EM (Caught e l) a -> (e -> EM l a) -> EM l a
catch = ... --omitted, as before

data Caught e l
instance Throws e (Caught e l)
instance Throws e l => Throws e (Caught e1 l)

parse :: Throws ParseError l => String -> EM l Expr
run :: ... => String -> ...
run str = do
e <- parse str `catch` \DivByZero -> ...
eval e

(`catch` \DivByZero -> ..) :: EM (Caught DivByZero l2) a -> EM l2 a

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Implementing Catch
|C| = c |H| = h
|catch C (λe → H)| = (c \ {e}) ∪ h

catch :: Exception e => EM (Caught e l) a -> (e -> EM l a) -> EM l a
catch = ... --omitted, as before

data Caught e l
instance Throws e (Caught e l)
instance Throws e l => Throws e (Caught e1 l)

parse :: Throws ParseError l => String -> EM l Expr
run :: ... => String -> ...
run str = do
e <- parse str `catch` \DivByZero -> ...
eval e

(`catch` \DivByZero -> ..) :: EM (Caught DivByZero l2) a -> EM l2 a
parse str :: Throws ParseError l1 => EM l1 Expr

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Implementing Catch
|C| = c |H| = h
|catch C (λe → H)| = (c \ {e}) ∪ h

catch :: Exception e => EM (Caught e l) a -> (e -> EM l a) -> EM l a
catch = ... --omitted, as before

data Caught e l
instance Throws e (Caught e l)
instance Throws e l => Throws e (Caught e1 l)

parse :: Throws ParseError l => String -> EM l Expr
run :: ... => String -> ...
run str = do
e <- parse str `catch` \DivByZero -> ...
eval e

(`catch` \DivByZero -> ..) :: EM (Caught DivByZero l2) a -> EM l2 a
parse str :: Throws ParseError l1 => EM l1 Expr
parse `catch` \DivByZero... :: Throws ParseError (Caught DivByZero l2) => EM l2 Expr

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Implementing Catch
|C| = c |H| = h
|catch C (λe → H)| = (c \ {e}) ∪ h

catch :: Exception e => EM (Caught e l) a -> (e -> EM l a) -> EM l a
catch = ... --omitted, as before

data Caught e l
instance Throws e (Caught e l)
instance Throws e l => Throws e (Caught e1 l)

parse :: Throws ParseError l => String -> EM l Expr
run :: ... => String -> ...
run str = do
e <- parse str `catch` \DivByZero -> ...
eval e

(`catch` \DivByZero -> ..) :: EM (Caught DivByZero l2) a -> EM l2 a
parse str :: Throws ParseError l1 => EM l1 Expr
parse `catch` \DivByZero... :: Throws ParseError l2 => EM l2 Expr

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Running EM computations
• Checked version demanding that no exceptions leak:

runEM :: EM l a -> a
runEM (EM (Right x)) = x

:t parse “some string”
parse “some string” :: Throws ParseError l => EM l Expr

:t runEM (parse “some string”)
No instance for (Throws ParseError l)
Possible fix:
add an instance declaration for (Throws ParseError l)

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Running EM computations
• Unchecked version accepting computations which may
raise any exception

data Any
instance Throws e Any

tryEM :: EM Any a -> Either SomeException a
tryEM (EM x) = x

:t tryEM (parse “this”)
tryEM (parse “this”) :: Either SomeException Expr

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Running EM computations
• Unchecked version accepting computations which may
raise any exception

data Any Any is a “type flag”
instance Throws e Any

tryEM :: EM Any a -> Either SomeException a
tryEM (EM x) = x

:t tryEM (parse “this”)
tryEM (parse “this”) :: Either SomeException Expr

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Running EM computations
• Unchecked version accepting computations which may
raise any exception

data Any
instance Throws e Any

tryEM :: EM Any a -> Either SomeException a
tryEM (EM x) = x

:t tryEM (parse “this”)
tryEM (parse “this”) :: Either SomeException Expr

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Running EM computations
• Selectively turning exceptions into unchecked exceptions

data OnlyUnchecked type flag
class Exception e => UncheckedException e
instance UncheckedException e => Throws e OnlyUnchecked

runEM :: EM OnlyUnchecked a -> a
runEM (EM (Right x)) = x
runEM (EM (Left e)) = error (“Unchecked exception: “ ++ show e)

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Running EM computations
• Selectively turning exceptions into unchecked exceptions

data OnlyUnchecked type flag
class Exception e => UncheckedException e
instance UncheckedException e => Throws e OnlyUnchecked

runEM :: EM OnlyUnchecked a -> a
runEM (EM (Right x)) = x
runEM (EM (Left e)) = error (“Unchecked exception: “ ++ show e)

parse :: Throws ParseError l => String -> EM l Expr
eval :: Throws DivByZero l => Expr -> EM l Double

instance UncheckedException ParseError

main :: String -> Double
main str = runEM $ do
e <- parse str
eval e `catch` \DivByZero -> ...

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

To check or not to check ?

“I used to think that checked exceptions were really
great” - Bruce Eckel*

“I completely agree that checked exceptions
are a wonderful feature. It’s just that existing
implementations are not”
Anders Heljsberg*

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

To check or not to check ?

“I used to think that checked exceptions were really
great” - Bruce Eckel*

“I completely agree that checked exceptions
are a wonderful feature. It’s just that existing
implementations are not”
Anders Heljsberg*

“Burritos* make great exception libraries” -
Jose Iborra
* - Monads are like Burritos, Brent Yorgey
José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

To check or not to check ?

“I used to think that checked exceptions were really
great” - Bruce Eckel*

“I completely agree that checked exceptions
are a wonderful feature. It’s just that existing
implementations are not”
Anders Heljsberg*

“Checked exceptions are great, in a library”
Jose Iborra

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Choice (of Monad)
class Monad m => MonadFailure e m where
failure :: e -> m a

instance MonadFailure e Maybe where failure _ = Nothing
instance Error e => MonadFailure e Either where failure = Left
instance Throws e l => MonadFailure e (EM l) where
failure = EM . Left . toException

parse :: (MonadFailure ParseError m) => String -> m Expr
eval :: (MonadFailure DivByZero m) => Expr -> m Double

run :: (MonadFailure DivByZero m, MonadFailure ParseError m) =>
String -> m Double

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Choice (of Monad)
class Monad m => MonadFailure e m where
failure :: e -> m a

instance MonadFailure e Maybe where failure _ = Nothing
instance Error e => MonadFailure e Either where failure = Left
instance Throws e l => MonadFailure e (EM l) where
failure = EM . Left . toException

parse :: (MonadFailure ParseError m) => String -> m Expr
eval :: (MonadFailure DivByZero m) => Expr -> m Double

run :: (MonadFailure DivByZero m, MonadFailure ParseError m) =>
String -> m Double

run :: (Throws DivByZero l, Throws ParseError l) => String -> EM l Double

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Choice (of Monad)
class Monad m => MonadFailure e m where
failure :: e -> m a

instance MonadFailure e Maybe where failure _ = Nothing
instance Error e => MonadFailure e Either where failure = Left
instance Throws e l => MonadFailure e (EM l) where
failure = EM . Left . toException

parse :: (MonadFailure ParseError m) => String -> m Expr
eval :: (MonadFailure DivByZero m) => Expr -> m Double

run :: (MonadFailure DivByZero m, MonadFailure ParseError m) =>
String -> m Double

run :: (Throws DivByZero l, Throws ParseError l) => String -> EM l Double

run :: String -> Maybe Double

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Explicitly Typed Exceptions for Haskell PADL’10

Choice (of Monad)
class Monad m => MonadFailure e m where
failure :: e -> m a

instance MonadFailure e Maybe where failure _ = Nothing
instance Error e => MonadFailure e Either where failure = Left
instance Throws e l => MonadFailure e (EM l) where
failure = EM . Left . toException

parse :: (MonadFailure ParseError m) => String -> m Expr
eval :: (MonadFailure DivByZero m) => Expr -> m Double

run :: (MonadFailure DivByZero m, MonadFailure ParseError m) =>
String -> m Double

run :: (Throws DivByZero l, Throws ParseError l) => String -> EM l Double

run :: String -> Maybe Double

run :: ...

José Iborra Universidad Politécnica de Valencia

Wednesday, January 20, 2010
Thanks

Wednesday, January 20, 2010