Skip to content

Commit 112ca0c

Browse files
committed
IO and MonadIO
1 parent 3a0b5e5 commit 112ca0c

File tree

1 file changed

+43
-0
lines changed

1 file changed

+43
-0
lines changed

content/covariance-contravariance.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -511,3 +511,46 @@ newtype E7 a = E7 ((() -> () -> a) -> a)
511511
newtype E8 a = E8 ((() -> a -> ()) -> a)
512512
newtype E9 a = E8 ((() -> () -> ()) -> ())
513513
```
514+
515+
## Lifting `IO` to `MonadIO`
516+
517+
Let's look at something seemingly unrelated to get a feel for the power of our
518+
new analysis tools. Consider the base function `openFile`:
519+
520+
```haskell
521+
openFile :: FilePath -> IOMode -> IO Handle
522+
```
523+
524+
We may want to use this from a monad transformer stack based on top of the `IO`
525+
monad. The standard approach to that is to use the `MonadIO` typeclass as a
526+
constraint, and its `liftIO` function. This is all rather straightforward:
527+
528+
```haskell
529+
import System.IO
530+
import Control.Monad.IO.Class
531+
532+
openFileLifted :: MonadIO m => FilePath -> IOMode -> m Handle
533+
openFileLifted fp mode = liftIO (openFile fp mode)
534+
```
535+
536+
But of course, we all prefer using the `withFile` function instead of
537+
`openFile` to ensure resources are cleaned up in the presence of exceptions. As
538+
a reminder, that function has a type signature:
539+
540+
```haskell
541+
withFile :: FilePath -> IOMode -> (Handle -> IO a) -> IO a
542+
```
543+
544+
So can we somehow write our lifted version with type signature:
545+
546+
```haskell
547+
withFileLifted :: MonadIO m => FilePath -> IOMode -> (Handle -> m a) -> m a
548+
```
549+
550+
Try as we might, this can't be done, at least not directly (if you're really
551+
curious, see [lifted-base](http://www.stackage.org/package/lifted-base) and its
552+
implementation of `bracket`). And now, we have the vocabulary to explain this
553+
succinctly: the `IO` type appears in both positive and negative position in
554+
`withFile`'s type signature. By contrast, with `openFile`, `IO` appears
555+
exclusively in positive position, meaning our transformation function
556+
(`liftIO`) can be applied to it.

0 commit comments

Comments
 (0)