Skip to content

Instantly share code, notes, and snippets.

@pomadchin
Last active June 21, 2020 00:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pomadchin/49cb6f0f6a1182e5bf8c99f942115e06 to your computer and use it in GitHub Desktop.
Save pomadchin/49cb6f0f6a1182e5bf8c99f942115e06 to your computer and use it in GitHub Desktop.
// an example of an unsafe function
def parseDouble(str: String): Double = java.lang.Double.parseDouble(str)
// that's how the dirty function can be wrapped
def parseDoubleF[F[_]: UnsafeLift](str: String): F[Double] =
UnsafeLift[F].apply(parseDouble(str))
parseDoubleF[IO]("ss").attempt.unsafeRunSync() //> Left(java.lang.NumberFormatException: For input string: "ss"): Either[Throwable, Double]
parseDoubleF[Option]("ss") //> None
parseDoubleF[Try]("ss") //> Failure(java.lang.NumberFormatException: For input string: "ss"): scala.util.Try[Double]
import cats.{Id, ~>}
import cats.effect.{Sync, IO}
import scala.concurrent.{ExecutionContext, Future}
import scala.util.{Failure, Success, Try}
/** Type class that allows to handle unsafe calls */
trait UnsafeLift[F[_]] { self =>
def apply[A](value: => A): F[A]
def mapK[G[_]](f: F ~> G): UnsafeLift[G] = new UnsafeLift[G] {
def apply[A](value: => A): G[A] = f(self.apply(value))
}
}
object UnsafeLift {
def apply[F[_]: UnsafeLift]: UnsafeLift[F] = implicitly[UnsafeLift[F]]
// dummy instances
implicit val liftId: UnsafeLift[Id] = new UnsafeLift[Id] {
def apply[A](value: => A): Id[A] = value
}
implicit def liftSync[F[_]: Sync]: UnsafeLift[F] = new UnsafeLift[F] {
def apply[A](value: => A): F[A] = Sync[F].delay(value)
}
implicit def liftFuture(implicit ec: ExecutionContext): UnsafeLift[Future] = new UnsafeLift[Future] {
def apply[A](value: => A): Future[A] = Future(value)
}
implicit val liftOption: UnsafeLift[Option] = new UnsafeLift[Option] {
def apply[A](value: => A): Option[A] = Try(value).toOption
}
implicit val liftEither: UnsafeLift[Either[Throwable, *]] = new UnsafeLift[Either[Throwable, *]] {
def apply[A](value: => A): Either[Throwable, A] = Try(value) match {
case Success(value) => Right(value)
case Failure(e) => Left(e)
}
}
implicit val liftTry: UnsafeLift[Try] = new UnsafeLift[Try] {
def apply[A](value: => A): Try[A] = Try(value)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment