Play's JSON library includes a Functor
and Invariant Functor
:
I've seen Functor
before:
trait Functor[M[_]] extends Variant[M] {
def fmap[A, B](m: M[A], f: A => B): M[B]
}
But, conceptually, why is it necessary to provide both functions f1
and f2
for InvariantFunctor
?
trait InvariantFunctor[M[_]] extends Variant[M] {
def inmap[A, B](m: M[A], f1: A => B, f2: B => A): M[B]
}
In this answer I give a quick explanation of why Writes
isn't a functor—i.e., why if we have a Writes[A]
and a function A => B
we can't create a Writes[B]
in the same way that we could with Reads
.
As I note in that answer, Writes
isn't an ordinary (covariant) functor, but it is a contravariant functor, which means that if we have a Writes[A]
and a function B => A
, we can create a Writes[B]
.
Format
subsumes the functionality of both Reads
and Writes
, which means that it's neither a functor nor an contravariant functor—but it is an invariant functor (and it's really the only type with an invariant functor instance that you'll run into in the context of Play).
To see why this is so, suppose we have the following two types:
case class Foo(i: Int, s: String)
case class Bar(s: String, i: Int)
And suppose we've got a Format
instance for Foo
:
import play.api.libs.json._
import play.api.libs.functional.syntax._
implicit val fooFormat = Json.format[Foo]
But that for whatever reason we can't create one in the same way for Bar
—we want to derive it from the one for Foo
. It's not enough for us to know how to create a Bar
from a Foo
, or vice versa, but if we can go both ways, we can use the invariant functor for Format
:
implicit val barFormat = fooFormat.inmap[Bar](
foo => Bar(foo.s, foo.i),
bar => Foo(bar.i, bar.s)
)
This is because we can think of Format
as a two-way pipe that allows us to put in a JsValue
and get out some A
, or to put in that A
and get out a JsValue
. If we want to convert a two-way pipe Format[A]
into a two-way pipe Format[B]
, we need adapters for both sides (i.e., both A => B
and B => A
).
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