2018-01-04 15:31:00 +00:00
|
|
|
---
|
|
|
|
title: Exceptions, transformers, primitive
|
|
|
|
---
|
2018-01-03 13:41:42 +00:00
|
|
|
|
2018-01-04 15:31:00 +00:00
|
|
|
# Exceptions, transformers, primitive
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
## Error handling
|
|
|
|
|
|
|
|
Let's discuss the different ways you can handle errors in general
|
|
|
|
|
|
|
|
----
|
|
|
|
|
|
|
|
## Explicit return checking
|
|
|
|
|
|
|
|
Examples: C, Go
|
|
|
|
|
|
|
|
```
|
|
|
|
if err != nil { return err }
|
|
|
|
```
|
|
|
|
|
|
|
|
Explicit, obvious, tedious, easy to forget
|
|
|
|
|
|
|
|
----
|
|
|
|
|
|
|
|
## Explicit with sum types
|
|
|
|
|
|
|
|
Examples: none?
|
|
|
|
|
|
|
|
```haskell
|
|
|
|
eres1 <- doSomething
|
|
|
|
case eres1 of
|
|
|
|
Left e -> handleError1 e
|
|
|
|
Right x -> do
|
|
|
|
eres2 <- doSomething2 x
|
|
|
|
...
|
|
|
|
```
|
|
|
|
|
|
|
|
* Forced to consider `Left` case...
|
|
|
|
* Unless you don't care about the result (`putStrLn`)
|
|
|
|
|
|
|
|
----
|
|
|
|
|
|
|
|
## Sum types with language help
|
|
|
|
|
|
|
|
Examples: Rust
|
|
|
|
|
|
|
|
```rust
|
|
|
|
let x = doSomething()?;
|
|
|
|
let y = doSomething2(x);
|
|
|
|
```
|
|
|
|
|
|
|
|
* Bonus: compiler warning/error on ignored `Result`
|
|
|
|
* Less tedious, difficult to get wrong
|
|
|
|
* Have to wrangle different exception types
|
|
|
|
|
|
|
|
----
|
|
|
|
|
|
|
|
## Monad transformer
|
|
|
|
|
|
|
|
Examples: Haskell, others?
|
|
|
|
|
|
|
|
```haskell
|
|
|
|
foo :: ExceptT MyExceptionType IO Y
|
|
|
|
foo = do
|
|
|
|
x <- doSomething
|
|
|
|
y <- doSomething2 x
|
|
|
|
return y
|
|
|
|
```
|
|
|
|
|
|
|
|
* Explicit in the exception type
|
|
|
|
* ... assuming no exceptions in `IO` itself
|
|
|
|
* Still need to wrangle different exception types
|
|
|
|
|
|
|
|
----
|
|
|
|
|
|
|
|
## Unchecked runtime exceptions
|
|
|
|
|
|
|
|
Examples: almost everyone
|
|
|
|
|
|
|
|
```haskell
|
|
|
|
foo :: IO Y
|
|
|
|
foo = do
|
|
|
|
x <- doSomething
|
|
|
|
y <- doSomething2 x
|
|
|
|
return y
|
|
|
|
```
|
|
|
|
|
|
|
|
* No idea what can go wrong
|
|
|
|
* No tedium
|
|
|
|
* Much faster than transformers
|
|
|
|
* In Haskell, this means `SomeException` is thrown from `IO`, always
|
|
|
|
|
|
|
|
----
|
|
|
|
|
|
|
|
## Reality in Haskell
|
|
|
|
|
|
|
|
* `IO` _does_ have unchecked exceptions
|
|
|
|
* `ExceptT` over `IO` has `SomeException`
|
|
|
|
* My argument: `ExceptT` over `IO`, in practice, is a bad idea
|
|
|
|
* Question: if we designed Haskell from the ground up today, would we
|
|
|
|
still include unchecked exceptions?
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
## Nice things in Haskell
|
|
|
|
|
|
|
|
This code is nice
|
|
|
|
|
|
|
|
```haskell
|
|
|
|
timeout tenSeconds someHTTPRequest
|
|
|
|
```
|
|
|
|
|
|
|
|
So is this
|
|
|
|
|
|
|
|
```haskell
|
|
|
|
race fileWatcher userCode
|
|
|
|
```
|
|
|
|
|
|
|
|
How do we get this?
|
|
|
|
|
|
|
|
----
|
|
|
|
|
|
|
|
## Async exceptions
|
|
|
|
|
|
|
|
* Send exceptions to a thread from somewhere else
|
|
|
|
* No way to control what type of exception may be received
|
|
|
|
* Therefore: any `IO` action can receive an exception of any type
|
|
|
|
* Necessitates an unchecked exception world
|
|
|
|
* Once you have that, you have to assume `IO` can fail with anything
|
|
|
|
at any time
|
|
|
|
* Caveat: you can `mask` temporarily for resource cleanup purposes
|
|
|
|
|
|
|
|
----
|
|
|
|
|
|
|
|
## Dealing with async exceptions
|
|
|
|
|
|
|
|
<https://haskell-lang.org/library/safe-exceptions>
|
|
|
|
|
|
|
|
Same approach used by the new unliftio package, docs still in transition
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
## What about transformers?
|
|
|
|
|
|
|
|
* Already know `ExceptT` can address async exceptions
|
|
|
|
* Can we deal with synchronous exceptions in transformer code?
|
2018-01-03 13:41:42 +00:00
|
|
|
* https://www.snoyman.com/reveal/monad-transformer-state
|
|
|
|
* https://www.yesodweb.com/blog/2014/05/exceptions-cont-monads
|
|
|
|
|
2018-01-04 15:31:00 +00:00
|
|
|
---
|
2018-01-03 13:41:42 +00:00
|
|
|
|
2018-01-04 15:31:00 +00:00
|
|
|
## Exception handling best practices
|
2018-01-03 13:41:42 +00:00
|
|
|
|
|
|
|
* https://www.fpcomplete.com/blog/2016/11/exceptions-best-practices-haskell
|
|
|
|
|
2018-01-04 15:31:00 +00:00
|
|
|
---
|
|
|
|
|
|
|
|
## The RIO monad
|
|
|
|
|
|
|
|
<https://www.fpcomplete.com/blog/2017/07/the-rio-monad>
|
|
|
|
|
|
|
|
FIXME: More up-to-date explanation
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
## Still have time for more?
|
|
|
|
|
|
|
|
Let's play with some really fun stuff
|
2018-01-03 13:41:42 +00:00
|
|
|
|
|
|
|
* https://haskell-lang.org/tutorial/primitive-haskell
|
|
|
|
* <https://wiki.haskell.org/Evaluation_order_and_state_tokens>
|