Skip to content

Instantly share code, notes, and snippets.

@etorreborre
Created September 13, 2014 01:01
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save etorreborre/17172007514721addbff to your computer and use it in GitHub Desktop.
Save etorreborre/17172007514721addbff to your computer and use it in GitHub Desktop.
Why is MonadError helpful?
/**
* Let's say I can read things from a "Store"
*/
trait Store[F] {
def read(path: Path): F[String]
}
/**
* Now I want to read more specific things, like a Configuration
*
* If I can constrain the "F" in my store to be a Monad (a Functor would be enough)
* Then I can parse the configuration and return a Configuration object
*
* However:
*
* - I have no ways to return parsing errors
* - If I have a Store that already provides a notion of Error
* things might be a bit clumsy see == 1 ==
*/
object ConfigurationStorage {
val path: Path = Path("configuration")
def fromStore[F[_] : Monad](store: Store[F]): F[Option[Configuration]] =
store.read(path).map(parseConfiguration)
def parseConfiguration(conf: String): Option[Configuration] = ???
}
/**
* == 1 ==
*
* A Store with a Monad knowing about errors
* Using this store with the ConfigurationStorage would return
*
* val store: IOErrorStore = ???
* // too bad we can't use "Throwable" to indicate that the reading operation failed!
* val configuration: IO[Throwable \/ Option[Configuration]] =
* ConfigurationStorage.fromStore(store)
*/
trait IOErrorStore {
/**
* this type can do IO and store errors if
* a path can't be read.
* It is possible to implement the MonadError interface
* for this type
*/
type IOError[T] = IO[Throwable \/ T]
def read(path: Path): IOError[String]
}
/**
* Now, if I have a MonadError type I can do the following
* and register errors for any Monad that is also a MonadError
* (don't take this literally, a bit more is necessary to have all the types align correctly)
*/
object ConfigurationStorage {
val path: Path = Path("configuration")
def fromStore[F[_,_](store: Store[F])(implicit monad: MonadError[F, Throwable]): F[Configuration] =
store.read(path).flatMap { string => parseConfiguration(string) match {
case -\/(t) => monad.raiseError(t)
case \/-(configuration) => monad.point(configuration)
}}
def parseConfiguration(conf: String): Throwable \/ Configuration = ???
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment