Skip to content

Instantly share code, notes, and snippets.

@y-yu
Last active May 23, 2016 01:03
Show Gist options
  • Save y-yu/0b2dd773031db89d3914 to your computer and use it in GitHub Desktop.
Save y-yu/0b2dd773031db89d3914 to your computer and use it in GitHub Desktop.
階層構造を容易に拡張できる例外 ref: http://qiita.com/yyu/items/07d56112bc42938aee05
object DatabaseAndHttpException {
implicit val databaseException = new :->[DatabaseException, DatabaseAndHttpException] {
def cast(a: DatabaseException): DatabaseAndHttpException =
DatabaseAndHttpException(s"database: ${a.m}")
}
implicit val httpException = new :->[HttpException, DatabaseAndHttpException] {
def cast(a: HttpException): DatabaseAndHttpException =
DatabaseAndHttpException(s"http: ${a.m}")
}
}
trait RootException extends Throwable
case class DatabaseException(m: String) extends RootException
case class HttpException(m: String) extends RootException
trait FileException extends RootException
case class ReadException(m: String) extends FileException
case class WriteException(m: String) extends FileException
RootException
|
+---- DatabaseException
|
+---- HttpException
|
+---- FileException
|
+---- ReadException
|
+---- WriteException
case class DatabaseAndHttpException(m: String) extends RootException
RootException
|
+---- DatabaseException
|
+---- HttpException
|
+---- FileException
| |
| +---- ReadException
| |
| +---- WriteException
|
+---- DatabaseAndHttpException
def left[A](e: A) = Left[A, Unit](e)
val e1 = left(DatabaseException("db error"))
val e2 = left(HttpException("http error"))
val e3 = for {
a <- e1
b <- e2
} yield ()
Error:(18, 9) could not find implicit value for parameter L2: utils.:->[utils.DatabaseException,utils.HttpException]
a <- e1
^
val e3 = for {
a <- e1
b <- e2.as[DatabaseAndHttpException]
} yield ()
RootException
|
+---- DatabaseException
|
+---- HttpException
|
+---- FileException
| |
| +---- ReadException
| |
| +---- WriteException
|
+---- DatabaseAndHttpException
val e4 = for {
a <- e1
} yield ()
Error:(20, 9) could not find implicit value for parameter L2: utils.:->[utils.DatabaseException,L2]
a <- e1
^
val result = for {
x <- databaseService(???) // Either[DatabaseException, A]
y <- httpService(???) // Either[HttpException, A]
} yield ()
implicit def self[A]= new :->[A, A] {
def cast(a: A): A = a
}
trait FileException extends RootException
case class ReadException(m: String) extends FileException
case class WriteException(m: String) extends FileException
RootException
|
+---- FileException
|
+---- ReadException
|
+---- WriteException
val e5 = left(ReadException("file read error"))
val e6 = left(WriteException("file read error"))
val e7 = for {
a <- e5
b <- e6
} yield ()
Error:(29, 9) could not find implicit value for parameter L2: utils.:->[utils.ReadException,utils.WriteException]
a <- e5
^
val e7 = for {
a <- e5
b <- e6.as[FileException]
} yield ()
Error:(30, 17) could not find implicit value for parameter L2: utils.:->[utils.WriteException,utils.FileException]
b <- e6.as[FileException]
^
implicit def superclass[A, B >: A] = new :->[A, B] {
def cast(a: A): B = a
}
case class DatabaseAndHttpException(m: String) extends RootException
val e7 = for {
a <- e5
b <- e6.as[FileException]
} yield ()
trait RootException extends Throwable
case class DatabaseException(m: String) extends RootException
RootException
|
+---- DatabaseException
def string_of_int(i: Int): String = i.toString
implicit val float_of_int = new :->[Int, Float] {
def cast(a: Int): Float = a.toFloat
}
for {
x <- databaseService(???) // Either[DatabaseException, A]
y <- httpService(???) // Either[HttpException, A]
} yield ()
object Implicit {
implicit class ExceptionEither[L <: RootException, R](val ee: Either[L, R]) {
def map[L2 <: RootException, R2](f: R => R2)(implicit L2: L :-> L2): Either[L2, R2] = ee match {
case Left(e) => Left(L2.cast(e))
case Right(v) => Right(f(v))
}
def flatMap[L2 <: RootException, R2](f: R => Either[L2, R2])(implicit L2: L :-> L2): Either[L2, R2] = ee match {
case Left(e) => Left(L2.cast(e))
case Right(v) => f(v)
}
def as[L2 <: RootException](implicit L2: L :-> L2): Either[L2, R] = ee match {
case Left(e) => Left(L2.cast(e))
case Right(v) => Right(v)
}
}
}
object :-> {
implicit def superclass[A, B >: A] = new :->[A, B] {
def cast(a: A): B = a
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment