base-io-access: The IO functions included in base delimited into small, composable classes

[ gpl, library, system ] [ Propose Tags ]

An attempt to break up the monolithic IO monad into small, composable classes that can be used to restrict a function to only having access to, say, functions to work with the standard pipes, or a function that can access the environment. The motivation for this library is to allow people to make a stricter contract than simply "this function does IO", and express through the type system exactly what IO is being performed.


[Skip to Readme]
Versions [faq] 0.2.0.0, 0.2.1.0, 0.2.2.0, 0.3.0.0, 0.3.0.1, 0.4.0.0
Dependencies base (==4.6.*) [details]
License GPL-2.0-only
Author Aaron Stevens
Maintainer bheklilr2@gmail.com
Category System
Home page https://github.com/bheklilr/base-io-access
Source repo head: git clone git://github.com/bheklilr/base-io-access.git
Uploaded by bheklilr at Sat Dec 28 04:55:36 UTC 2013
Distributions NixOS:0.4.0.0
Downloads 2725 total (12 in the last 30 days)
Rating (no votes yet) [estimated by rule of succession]
Your Rating
  • λ
  • λ
  • λ
Status Hackage Matrix CI
Docs available [build log]
Successful builds reported [all 1 reports]

Modules

[Index]

Downloads

Maintainer's Corner

For package maintainers and hackage trustees


Readme for base-io-access-0.3.0.1

[back to package description]

base-io-access

An attempt to break up the monolithic IO monad into small, composable classes that can be used to restrict a function to only having access to, say, functions to work with the standard pipes, or a function that can access the environment. The motivation for this library is to allow people to make a stricter contract than simply "this function does IO", and express through the type system exactly what IO is being performed.

Implementation

The method used is to make a thinly veiled class breaking up groups of IO actions into smaller sub-groups. As an example:

class Access io => ExitAccess io where
    exitWith'       :: ExitCode -> io a
    exitFailure'    :: io a
    exitSuccess'    :: io a

instance ExitAccess IO where
    exitWith'    = exitWith
    exitFailure' = exitFailure
    exitSuccess' = exitSuccess

Here the Access class is an empty super class that combines Monad, Applicative, Functor, Typeable1, and MonadFix. It is the super class for all the others in this library. Maybe eventually I will make it more powerful, or add in special support for handling generic Access actions, but for now it's going to remain very simplistic.

In this example taken from Access.System.Exit, we have defined a small class ExitAccess that has three functions, each corresponding to their implementation in System.Exit but with an extra ' appended to the name. By itself this class isn't very interesting, but when combined with (the larger ) StdIOAccess class, we could write a function like

helpMessage :: (ExitAccess io, StdIOAcess io) => io ()
helpMessage = do
    putStrLn' "Usage:"
    putStrLn' "    mytool [options]"
    putStrLn' "Options:"
    putStrLn' "    --help       Display this help message"
    exitSuccess'

main :: IO ()
main = do
    args <- getArgs
    if "--help" `elem` args
        then helpMessage
        else mainLoop

While this is a simple and contrived example, it illustrates that a function's capabilities are greatly reduced through this method. Since we often want to use the most restrictive type we can in Haskell, this provides an easy way to achieve this when working with the all-encompassing IO monad.

Performance

Since the entire library is based on just using typeclasses, there is no runtime overhead whatsoever. The compiler will optimize away the class lookups, and every function is simply a thin wrapper around its actual implementation in base.