Last active
June 21, 2020 00:58
-
-
Save pomadchin/49cb6f0f6a1182e5bf8c99f942115e06 to your computer and use it in GitHub Desktop.
UnsafeLift type class example: https://scastie.scala-lang.org/pomadchin/bHEGJRdXTB6EgO6xb22ILw
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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