Skip to content

Instantly share code, notes, and snippets.

@neko-kai
Created June 13, 2018 15:56
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save neko-kai/00c5ef96c1c1679a1edf7056ea55b49d to your computer and use it in GitHub Desktop.
Save neko-kai/00c5ef96c1c1679a1edf7056ea55b49d to your computer and use it in GitHub Desktop.
difference between mtl-style and tagless final style
import cats._
import cats.implicits._
trait MonadRandom[F[_]] {
def getRandom: F[Int]
}
final case class DummyRandom[A](a: A)
final case class RealRandom[A](a: A)
object MonadRandom {
implicit val dummyRandom: MonadRandom[DummyRandom] = new MonadRandom[DummyRandom] {
override def getRandom: DummyRandom[Int] = DummyRandom(5)
}
implicit val realRandom: MonadRandom[RealRandom] = new MonadRandom[RealRandom] {
override def getRandom: RealRandom[Int] = RealRandom { queryRandomDotOrg() }
}
def apply[F[_]: MonadRandom]: MonadRandom[F] = implicitly[MonadRandom[F]]
}
class ServiceImpl[F[_]: Monad: MonadRandom] {
def printRandom: F[Unit] = MonadRandom[F].getRandom.map(println(_))
}
def queryRandomDotOrg(): Int = ???
// Haskell MTL-style:
// To choose between impls: replace the Monad
// ServiceImpl[DummyRandom]
// ServiceImpl[RealRandom]
// Scala Tagless Final:
// To choose between impls: replace the Service
// DummyServiceImpl[IO]
// RealServiceImpl[IO]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment