How to define an implicit converter to a Monad? - scalaz

I'm defining a trait which has an abstract type B which I want to use as a monad. To specify that B must be able to act as a monad, I declare an implicit monadB:
trait A {
type B[_]
implicit def monadB: Monad[B]
}
Then, when I implement this type, I assign a concrete type to B, such as List. I then need to provide a concrete definition for the implicit monadB. It is needed, for example, when calling the method .point[B] in the function randomDouble below. How can I do it?
trait A2 extends A {
type B[_] = List[_]
implicit def monadB: Monad[B] = ???
def randomDouble: B[Double] = new Random.nextDouble.point[B]
}
I've tried:
implicit def monadB: Monad[B] = implicitly[Monad[B]]
but this gets stuck in a infinite loop at runtime, I suppose because implicitly itself relies on an the corresponding implicit value. I guess I need to say that the implicit value for Monad[B] is actually the same as the implicit value for Monad[List], since B[_] = List[_]. But unfortunately,
implicit def monadB: Monad[B] = implicitly[Monad[List]]
doesn't work either, because Monad is invariant in it's type parameter (which, if I get it, means that Monad[List] can't be used in place of Monad[B], even though B = List).
I'm stuck. How do I define monadB?

There are two other ways that you might want to consider:
You can simply have:
def randomDouble[B[_]](implicit monadB: Monad[B]): B[Double] = (new Random).nextDouble.point[B]
and then you can use it like that: println(randomDouble[List]), so you don't tie randomDouble to any specific monad.
Alternatively, if you insist on using traits:
trait A {
type B[_]
implicit def monadB: Monad[B]
}
trait A2 extends A {
def randomDouble: B[Double] = (new Random).nextDouble.point[B]
}
def a2[A[_]](implicit m: Monad[A]) = new A2 {
type B[C] = A[C]
implicit val monadB = m
}
and then you use it println(a2[List].randomDouble) and again you don't tie A2 nor a2 to any specific monad.

It turns out that specifying the internal abstract type with a symbol rather than leaving a _ makes it possible to use implicitly[Monad[List]]:
trait A2 extends A {
type B[A] = List[A]
implicit def monadB: Monad[B] = implicitly[Monad[List]]
def randomDouble: B[Double] = new Random.nextDouble.point[B]
}
While it works, I don't have any explanation as of why.

Related

Scala, spray-json: universal enumeration json formatting

I have such model: two enumerations and one case class with two fields of these enums types:
// see later, why objects are implicit
implicit object Fruits extends Enumeration {
val Apple = Value("apple")
val Orange = Value("orange")
}
implicit object Vegetables extends Enumeration {
val Potato = Value("potato")
val Cucumber = Value("cucumber")
val Tomato = Value("tomato")
}
type Fruit = Fruits.Value
type Vegetable = Vegetables.Value
case class Pair(fruit: Fruit, vegetable: Vegetable)
I want to parse/generate JSONs to/from Pairs with spray-json. I don't want to declare separate JsonFormats for fruits and vegetables. So, I'd like to do something like this:
import spray.json._
import spray.json.DefaultJsonProtocol._
// enum is implicit here, that's why we needed implicit objects
implicit def enumFormat[A <: Enumeration](implicit enum: A): RootJsonFormat[enum.Value] =
new RootJsonFormat[enum.Value] {
def read(value: JsValue): enum.Value = value match {
case JsString(s) =>
enum.withName(s)
case x =>
deserializationError("Expected JsString, but got " + x)
}
def write(obj: enum.Value) = JsString(obj.toString)
}
// compilation error: couldn't find implicits for JF[Fruit] and JF[Vegetable]
implicit val pairFormat = jsonFormat2(Pair)
// expected value:
// spray.json.JsValue = {"fruit":"apple","vegetable":"potato"}
// but actually doesn't even compile
Pair(Fruits.Apple, Vegetables.Potato).toJson
Sadly, enumFormat doesn't produce implicit values for jsonFormat2. If I write manually two implicit declarations before pairFormat for fruits and vegetables formats, then json marshalling works:
implicit val fruitFormat: RootJsonFormat[Fruit] = enumFormat(Fruits)
implicit val vegetableFormat: RootJsonFormat[Vegetable] = enumFormat(Vegetables)
implicit val pairFormat = jsonFormat2(Pair)
// {"fruit":"apple","vegetable":"potato"}, as expected
Pair(Fruits.Apple, Vegetables.Potato).toJson
So, two questions:
How to get rid of these fruitFormat and vegetableFormat declarations?
Ideally it would be great to not make enumeration objects implicit, while keeping enumFormat function generic. Is there a way to achieve this? Maybe, using scala.reflect package or something like that.
You just have to replace enum.Value with A#Value.
Looking at spray-json #200 you can find an example of a well defined implicit enumFormat, slightly modified to leverage implicit enu retrieval:
implicit def enumFormat[T <: Enumeration](implicit enu: T): RootJsonFormat[T#Value] =
new RootJsonFormat[T#Value] {
def write(obj: T#Value): JsValue = JsString(obj.toString)
def read(json: JsValue): T#Value = {
json match {
case JsString(txt) => enu.withName(txt)
case somethingElse => throw DeserializationException(s"Expected a value from enum $enu instead of $somethingElse")
}
}
}
You can't, Scala doesn't allow implicit chaining, because it would lead to combinatorial explosions that would make the compiler too slow.
See https://docs.scala-lang.org/tutorials/FAQ/chaining-implicits.html
Scala does not allow two such implicit conversions taking place, however, so one cannot got from A to C using an implicit A to B and another implicit B to C.
You'll have to explicitly produce a JsonFormat[T] for each T you want to use.

Scala Play: how to define a "Json writable class"

I would like to write a function that transforms case classes to Json:
import play.api.libs.json._
def myJson(cc: Product): JsValue = {
Json.toJson(cc) // simplified
}
Each case class has an implicit Writes[T], for example:
case class Test(a: Int)
object Test {
implicit val jsonWrites: Writes[Test] = Json.writes[Test]
}
It is possible to write Json.toJson(new Test(1)) individually, but the myJson function above does not compile because it never knows if cc has an implicit Writes defined.
[How can I write the function signature so that it takes only classes having a Writes implicit?]
Edit: How can I write the function input type so that it corresponds only to classes having a Writes implicit?
I tried this:
trait JsonWritableResult[T <: Product] {
implicit val jsonWrites: Writes[T]
}
case class Test(a: Int)
object Test extends JsonWritableResult[Test] {
implicit val jsonWrites: Writes[Test] = Json.writes[Test]
}
def myJson(cc: JsonWritableResult[_ <: Product]): JsValue = {
Json.toJson(cc)
}
But it says "No Json serializer found for type models.JsonWritableResult[_$2]".
Something like this seems to give you the behavior you want.
import play.api.libs.json.{JsValue, Json, Writes}
trait Product {}
case class Test(a: Int) extends Product
object Test {
implicit val jsonWrites: Writes[Test] = Json.writes[Test]
}
def myJson[T <: Product](cc: T)(implicit writes: Writes[T]): JsValue = {
Json.toJson(cc) // simplified
}
import Test._
myJson(Test(3))
This is not tested in the general case, but in a Worksheet it seems to work.
Instead of forcing the case class to have the implicit, it is more clever to force it to override a toJson method from a trait, using or not an implicit defined in the case class. Much simpler and it works. Then my factory can explicit this trait in its output type, and thus I can serialize whatever it outputs.
But since the other answer answered the question that I formulated wrong, I accept it ;)

Json "Validate" for Play

For the validate method on request.body it matches the attribute name and value type of the json object to those defined in the model definition. Now if I were to add an extra attribute to the json object and try to validate it, it passes as a JsSuccess when it shouldn't.
{
"Name": "Bob",
"Age": 20,
"Random_Field_Not_Defined_in_Models": "Test"
}
My Person Class is defined as follows
case class Person(name: String, age: Int)
I'm assuming you've been using the built-in Reads[T] or Format[T] converters that Play gives you via Json.reads[T], e.g.:
import play.api.libs.json._
val standardReads = Json.reads[Person]
While these are super-handy, if you need additional validation, you'll have to define a custom Reads[Person] class; but fortunately we can still leverage the built-in JSON-to-case-class macro to do the basic checking and conversion, and then add an extra layer of custom checks if things seem OK:
val standardReads = Json.reads[Person]
val strictReads = new Reads[Person] {
val expectedKeys = Set("name", "age")
def reads(jsv:JsValue):JsResult[Person] = {
standardReads.reads(jsv).flatMap { person =>
checkUnwantedKeys(jsv, person)
}
}
private def checkUnwantedKeys(jsv:JsValue, p:Person):JsResult[Person] = {
val obj = jsv.asInstanceOf[JsObject]
val keys = obj.keys
val unwanted = keys.diff(expectedKeys)
if (unwanted.isEmpty) {
JsSuccess(p)
} else {
JsError(s"Keys: ${unwanted.mkString(",")} found in the incoming JSON")
}
}
}
Note how we utilize standardReads first, to make sure we're dealing with something that can be converted to a Person. No need to reinvent the wheel here.
We use flatMap to effectively short-circuit the conversion if we get a JsError from standardReads - i.e. we only call checkUnwantedKeys if needed.
checkUnwantedKeys just uses the fact that a JsObject is really just a wrapper around a Map, so we can easily check the names of the keys against a whitelist.
Note that you could also write that flatMap using a for-comprehension, which starts to look a lot cleaner if you need even more checking stages:
for {
p <- standardReads.reads(jsv)
r1 <- checkUnexpectedFields(jsv, p)
r2 <- checkSomeOtherStuff(jsv, r1)
r3 <- checkEvenMoreStuff(jsv, r2)
} yield r3
If you want to avoid too much boilerplate it is possible to make a more generic solution using a little bit of scala reflection:
import play.api.libs.json._
import scala.reflect.runtime.universe._
def checkedReads[T](underlyingReads: Reads[T])(implicit typeTag: TypeTag[T]): Reads[T] = new Reads[T] {
def classFields[T: TypeTag]: Set[String] = typeOf[T].members.collect {
case m: MethodSymbol if m.isCaseAccessor => m.name.decodedName.toString
}.toSet
def reads(json: JsValue): JsResult[T] = {
val caseClassFields = classFields[T]
json match {
case JsObject(fields) if (fields.keySet -- caseClassFields).nonEmpty =>
JsError(s"Unexpected fields provided: ${(fields.keySet -- caseClassFields).mkString(", ")}")
case _ => underlyingReads.reads(json)
}
}
}
Then you can specify your reads instances as:
implicit val reads = checkedReads(Json.reads[Person])
This leverages a fair bit of Scala type magic and also the reflection library (that lets you look at fields on classes).
Rather than relying on a fixed set of fields the classFields method gets all of the fields dynamically for the case class (type param T). It looks at all of the members and collects only the case class accessors (otherwise we'd pick up methods like toString). It returns a Set[String] of field names.
You'll notice that the checkedReads takes an implicit TypeTag[T]. This is supplied by the compiler at compile time and used by the typeOf method.
The remaining code is fairly self explanatory. If the incoming json matches our first case (it is a JsObject and there are fields not on the case class) then we return a JsError. Otherwise we pass it on to the underlying reader.

How to fail on json with unused fields in play-json scala? [duplicate]

For the validate method on request.body it matches the attribute name and value type of the json object to those defined in the model definition. Now if I were to add an extra attribute to the json object and try to validate it, it passes as a JsSuccess when it shouldn't.
{
"Name": "Bob",
"Age": 20,
"Random_Field_Not_Defined_in_Models": "Test"
}
My Person Class is defined as follows
case class Person(name: String, age: Int)
I'm assuming you've been using the built-in Reads[T] or Format[T] converters that Play gives you via Json.reads[T], e.g.:
import play.api.libs.json._
val standardReads = Json.reads[Person]
While these are super-handy, if you need additional validation, you'll have to define a custom Reads[Person] class; but fortunately we can still leverage the built-in JSON-to-case-class macro to do the basic checking and conversion, and then add an extra layer of custom checks if things seem OK:
val standardReads = Json.reads[Person]
val strictReads = new Reads[Person] {
val expectedKeys = Set("name", "age")
def reads(jsv:JsValue):JsResult[Person] = {
standardReads.reads(jsv).flatMap { person =>
checkUnwantedKeys(jsv, person)
}
}
private def checkUnwantedKeys(jsv:JsValue, p:Person):JsResult[Person] = {
val obj = jsv.asInstanceOf[JsObject]
val keys = obj.keys
val unwanted = keys.diff(expectedKeys)
if (unwanted.isEmpty) {
JsSuccess(p)
} else {
JsError(s"Keys: ${unwanted.mkString(",")} found in the incoming JSON")
}
}
}
Note how we utilize standardReads first, to make sure we're dealing with something that can be converted to a Person. No need to reinvent the wheel here.
We use flatMap to effectively short-circuit the conversion if we get a JsError from standardReads - i.e. we only call checkUnwantedKeys if needed.
checkUnwantedKeys just uses the fact that a JsObject is really just a wrapper around a Map, so we can easily check the names of the keys against a whitelist.
Note that you could also write that flatMap using a for-comprehension, which starts to look a lot cleaner if you need even more checking stages:
for {
p <- standardReads.reads(jsv)
r1 <- checkUnexpectedFields(jsv, p)
r2 <- checkSomeOtherStuff(jsv, r1)
r3 <- checkEvenMoreStuff(jsv, r2)
} yield r3
If you want to avoid too much boilerplate it is possible to make a more generic solution using a little bit of scala reflection:
import play.api.libs.json._
import scala.reflect.runtime.universe._
def checkedReads[T](underlyingReads: Reads[T])(implicit typeTag: TypeTag[T]): Reads[T] = new Reads[T] {
def classFields[T: TypeTag]: Set[String] = typeOf[T].members.collect {
case m: MethodSymbol if m.isCaseAccessor => m.name.decodedName.toString
}.toSet
def reads(json: JsValue): JsResult[T] = {
val caseClassFields = classFields[T]
json match {
case JsObject(fields) if (fields.keySet -- caseClassFields).nonEmpty =>
JsError(s"Unexpected fields provided: ${(fields.keySet -- caseClassFields).mkString(", ")}")
case _ => underlyingReads.reads(json)
}
}
}
Then you can specify your reads instances as:
implicit val reads = checkedReads(Json.reads[Person])
This leverages a fair bit of Scala type magic and also the reflection library (that lets you look at fields on classes).
Rather than relying on a fixed set of fields the classFields method gets all of the fields dynamically for the case class (type param T). It looks at all of the members and collects only the case class accessors (otherwise we'd pick up methods like toString). It returns a Set[String] of field names.
You'll notice that the checkedReads takes an implicit TypeTag[T]. This is supplied by the compiler at compile time and used by the typeOf method.
The remaining code is fairly self explanatory. If the incoming json matches our first case (it is a JsObject and there are fields not on the case class) then we return a JsError. Otherwise we pass it on to the underlying reader.

transitive implicits - is this possible in Scala?

Let's say I have several functions:
func1 : A => B
func2: B => C
func3: C => D
I would like to orchestrate now functions when needed in a generic fashion.
let's say if i need a conversion from A to B I'd call func1.
But when I need a conversion from A to D I would like to have a composition of those functions. Is such thing possible in a dynamic notion?
From the Scala documentation for language features, explaining why implicit conversions have to be explicitly enabled in 2.10:
Why control it? Implicit conversions are known to cause many pitfalls
if over-used. And there is a tendency to over-use them because they
look very powerful and their effects seem to be easy to understand.
Also, in most situations using implicit parameters leads to a better
design than implicit conversions.
User-defined implicit conversions are almost always a bad idea, and making them transitive would be much, much worse.
You can, however, use type classes to get a similar effect in a much safer, more controlled way. For example, suppose we have the following:
trait MyConverter[A, B] { def apply(a: A): B }
implicit def composeMyConverters[A, B, C](implicit
ab: MyConverter[A, B],
bc: MyConverter[B, C]
) = new MyConverter[A, C] { def apply(a: A) = bc(ab(a)) }
Now we can write:
implicit object doubleToString extends MyConverter[Double, String] {
def apply(d: Double) = d.toString
}
implicit object intToDouble extends MyConverter[Int, Double] {
def apply(i: Int) = i.toDouble
}
def convertToString[A](a: A)(implicit as: MyConverter[A, String]) = as(a)
And finally:
scala> convertToString(13: Int)
res0: String = 13.0
We've never explicitly defined a converter from integers to strings, but the compiler is able to use our composeMyConverters method to construct one when it's needed.
Like implicit conversions, this approach can also be abused, but it's much easier to keep tabs on what converters are in scope, where they're being applied, etc.