Implicit function types are planned to land in Scala 3.0, and claimed to support "effect capabilities" and composable. It is presented as a better alternative to monad transformers. However, reading further explanation it just seems that implicit function types can only model Reader monad. Am I missing something?
Immediately, it is most trivial to notice that implicit function types allow us to encode the Reader monad primarily allocation free, but losing the convenient for comprehension syntax.
I think what Odersky is referring to when he talks about "a better alternative to monad transformers" is the fact that implicit function types allow you to encode a rather boilerplate free free monad (no pun intended), which is one approach to composing monadic effects.
From the following comment on discourse (emphasis mine):
I guess we both agree that in the future we will have very fine-grained effect systems, so much so that a lot of code with be effectful in some way or another. But then you end up with large parts of your program written in monad structure. The structure itself does not tell you which effects the code has; you need to turn to the types for that.
On the other hand, every time you introduce a new effect category (and it could be as ubiquitous as “not proven to be total”) you need to completely refactor your code into the monadic scheme. And that means you are willing to take a slowdown of (I estimate) 10, risk stackoverflows, be extremely verbose, and have a really hard time composing all your fine grained effects. Or you go free which means better composition but likely even more boilerplate. I can see this work in the sense that you very forcefully tell your users: “don’t use effects, it’s just too painful”. So it could have education value. But if you have to deal with effects, it’s utterly suboptimal in several dimensions.
In his paper, Foundations of Implicit Function Types, Odersky lays out an alternative encoding for free monads using implicit function types which require less boilerplate:
// Free definition
type FreeIFT[A[_], M[_], T] = implicit Natural[A, M] => implicit Monad[M] => M[T]
// GADT defintion
enum KVStoreB[T] {
case Put(key: String, value: Int) extends KVStoreB[Unit]
case Get(key: String) extends KVStoreB[Option[Int]]
}
// Lifted definition
import KVStoreB._
type KVStoreIFT[M[_], T] = FreeIFT[KVStoreB, M, T]
def iftExpr[M[_]]: KVStoreIFT[M, Option[Int]] =
for {
_ <- Put("foo", 2).lift
_ <- Put("bar", 5).lift
n <- Get("foo").lift
} yield n
// Free interpeter
def iftInterpreter = new Natural[KVStoreB, Future] {
def apply[T](fa: KVStoreB[T]): Future[T] = ???
}
// Running the interpreter over the free structure
val iftOutput: Future[Option[Int]] = iftExpr[Future](iftInterpreter)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With