scalaz join operation requires type explicitly specified - scalaz

scala> Some(Some(9))
res23: Some[Some[Int]] = Some(Some(9))
scala> res23.join #plan a
<console>:24: error: value join is not a member of Some[Some[Int]]
res23.join
^
scala> ((Some(Some(9))):Option[Option[Int]]).join #plan b
res25: Option[Int] = Some(9)
thought plan a should be equivalent to plan b. why the type has to be explicitly specified?
Not only this, I've seen other places that parameter type has to be explicitly spelled out. Thought scala could do type inference, isn't it?

The answer is in your REPL :)
In the third line you declare an Option[Option[Int]] instead of a Some[Some[Int]] which is the type inferred in the first command.
Try:
scala> Option(Option(9)).join
res3: Option[Int] = Some(9)

Related

Json.fromJson not working for Int or Double

How can I resolve following implicit conflict? I converted a Double to JsValue using Json.toJson. The reverse process is not working. There is an implicit conflict.
scala> val doublejsv = Json.toJson(4.1)
doublejsv: play.api.libs.json.JsValue = 4.1
scala> Json.fromJson(doublejsv)
<console>:21: error: ambiguous implicit values:
both object IntReads in trait DefaultReads of type play.api.libs.json.Reads.IntReads.type
and object ShortReads in trait DefaultReads of type play.api.libs.json.Reads.ShortReads.type
match expected type play.api.libs.json.Reads[T]
Json.fromJson(doublejsv)
^
Use explicit type:
val double = Json.fromJson[Double](doublejsv)

Json#arr w/ List[Int] Input

Looking at this helpful answer on encoding a List[A] in the Play JSON library,
I tried to use Json#arr:
import play.api.libs.json._
scala> Json.arr( 1, 2, 3 )
res21: play.api.libs.json.JsArray = [1,2,3]
All works well so far, but what if I have a List[Int]:
scala> Json.arr( List(1,2,3) )
res22: play.api.libs.json.JsArray = [[1,2,3]] // not what I wanted
I attempted to pass the List[Int] as var-args (if that's the right term):
scala> Json.arr( List(1,2,3): _* )
<console>:18: error: type mismatch;
found : List[Int]
required: Seq[play.api.libs.json.Json.JsValueWrapper]
Json.arr( List(1,2,3): _* )
^
But that did not work.
Then, I tried to create a List[JsValueWrapper], and then pass that, via var-args, to Json#arr:
scala> List(1,2,3).map(Json.toJsFieldJsValueWrapper)
<console>:18: error: No Json serializer found for type T. Try to implement an implicit Writes or Format for this type.
List(1,2,3).map(Json.toJsFieldJsValueWrapper)
^
Although that failed, the following works when applied to a single Int:
scala> Json.toJsFieldJsValueWrapper(1)
res27: play.api.libs.json.Json.JsValueWrapper = JsValueWrapperImpl(1)
scala> Json.arr(res27)
res28: play.api.libs.json.JsArray = [1]
How can I pass a List[Int] into Json.arr to get an output of [1,2,3], i.e. a JsArray consisting of three JsNumber's?
You could use Json.toJson, validate as a JsArray, or return an empty one if invalid:
scala> val list = List(1, 2, 3)
list: List[Int] = List(1, 2, 3)
scala> Json.toJson(list).validate[JsArray].getOrElse(JsArray())
res6: play.api.libs.json.JsArray = [1,2,3]
You could also modify your lambda slightly with Json.arr:
scala> Json.arr(list.map(Json.toJsFieldJsValueWrapper(_)): _*)
res10: play.api.libs.json.JsArray = [1,2,3]
It seems as though without the parentheses, the compiler is having trouble inferring what T is. This is because the compiler tries to resolve the implicit before eta-expanding the anonymous function, so it doesn't know what argument will be passed to Json.toJsFieldJsValueWrapper yet. Json.toJsFieldJsValueWrapper(_) is fundamentally different because it expands to a slightly different Function1:
x => Json.toJsFieldJsValueWrapper(x)
Here the compiler knows that x will be an Int, so the implicit Writes[Int] is resolved.
How about just using Json.toJson and casting to a JsArray (if you need to)?
scala> Json.toJson(List(1,2,3)).as[JsArray]
res0: play.api.libs.json.JsArray = [1,2,3]

Defining Writes for case class that contains property whose type is a Map . Json / Scala / PlayFramework

I have a case class defined this way:
scala> import play.api.libs.json._
import play.api.libs.json._
scala> import play.api.libs.functional.syntax._
import play.api.libs.functional.syntax._
scala> type MapIntString = Map[Int, String]
defined type alias MapIntString
case class Duh(a: MapIntString)
defined class Duh
When I tried declaring its Writes this way, I got an error:
scala> implicit val duhWrites = Json.writes[Duh]
<console>:25: error: No implicit Writes for MapIntString available.
implicit val duhWrites = Json.writes[Duh]
So I resort to this..., still got an error:
scala> implicit val duhWrites: Writes[Duh] = (
| (JsPath \ "a").write[MapIntString]
| )(unlift(Duh.unapply _))
<console>:26: error: overloaded method value write with alternatives:
(t: MapIntString)(implicit w: play.api.libs.json.Writes[MapIntString])play.api.libs.json.OWrites[play.api.libs.json.JsValue] <and>
(implicit w: play.api.libs.json.Writes[MapIntString])play.api.libs.json.OWrites[MapIntString]
cannot be applied to (Duh => MapIntString)
(JsPath \ "a").write[MapIntString]
Can somebody help me pointing out where I did wrong?
I feel that my understanding of this reads/writes combinators a bit shaky. I posted related question here (when I was trying to understand what was going on): What is this "and" in ScalaJsonCombinator (when defining a Writes)?
If you know the best way to implement the Writes and Reads for "Duh" please share.
Thanks in advance!
There are no predefined Writes for Map[Int, String], only Map[String, A]. This is because all JSON keys must be a String, to Int keys don't really make any sense. You can fix this by defining one that converts the Int keys to Strings.
type MapIntString = Map[Int, String]
implicit val mapIntWrites = new Writes[MapIntString] {
def writes(m: MapIntString): JsValue =
Json.toJson(m.map { case (k, v) => (k.toString, v)} )
}
scala> implicit val duhWrites = Json.writes[Duh]
duhWrites: play.api.libs.json.OWrites[Duh] = play.api.libs.json.OWrites$$anon$2#50973f47

What is this "and" in ScalaJsonCombinator (when defining a Writes)?

I've been using this json combinator for several basic / standard cases without really understanding how it works. All was fine.
Now I want to get myself prepared for whatever advanced cases might come; I need to understand the code.
Ref.: https://www.playframework.com/documentation/2.3.x/ScalaJsonCombinators
I think I can understand the Reads:
implicit val locationReads: Reads[Location] = (
(JsPath \ "lat").read[Double] and
(JsPath \ "long").read[Double]
)(Location.apply _)
It creates a Reads that:
First -- when given a JsValue (through its "reads" method) -- it pulls the "lat", followed by the "long". Out of those two it creates a tuple (Double, Double). -- https://www.playframework.com/documentation/2.3.x/api/scala/index.html#play.api.libs.json.Reads
That tuple is then assigned to the partial function of that Reads..., which in this case is whatever returned by "Location.apply _". I tried it in repl:
...
scala> val yowMan = Location.apply _
yowMan: (Double, Double) => Location = <function2>
scala> yowMan(1, 2)
res14: Location = Location(1.0,2.0)
That partial function takes the a tuple of (Double, Double) as input. So..., the outcome of step 1 is channeled to step 2, and we get an instance of Location as the return of "reads".
Now for the Writes:
implicit val locationWrites: Writes[Location] = (
(JsPath \ "lat").write[Double] and
(JsPath \ "long").write[Double]
)(unlift(Location.unapply))
First the "unapply". I tried in repl:
scala> val heyDude = Location.unapply
<console>:16: error: missing arguments for method unapply in object Location;
follow this method with `_' if you want to treat it as a partially applied function
val heyDude = Location.unapply
Oops, ok, I followed the instruction:
scala> val heyDude = Location.unapply _
heyDude: Location => Option[(Double, Double)] = <function1>
Ok, so we get a partial function that transforms an instance of Location to an (optional) tuple of (Double, Double).
Next, the "unlift":
scala> val hohoho = unlift(heyDude)
hohoho: Location => (Double, Double) = <function1>
scala> val loc = Location(1, 2)
loc: Location = Location(1.0,2.0)
scala> hohoho(loc)
res16: (Double, Double) = (1.0,2.0)
Ok, so... unlift simply throws away the "Option", and takes us directly to the tuple.
Ok... so... I guess... this "writes" of the Writes... *) when given an instance of Location, it will:
Pass that object through that partial function produced by unlift(Location.unapply).
The tuple (Double, Double) returned by that partial function is then channeled to whatever is produced by this:
(JsPath \ "lat").write[Double] and
(JsPath \ "long").write[Double]
What exactly is that "whatever"? Following the API doc of JsPath, I think it is OWrites: https://www.playframework.com/documentation/2.3.x/api/scala/index.html#play.api.libs.json.OWrites
But... I can't see there's a method named "and" in OWrites. Where is this "and" declared? And what does it do? Is it: "oWrites1 and oWrites2" produces "oWrites3"? And this "oWrites3" is a special type of OWrites that takes tuple as input? ... If that's the case... the tuple doesn't have information about the name of the property in the case class ("lat" and "long"). How does it know that the produced json string should be {"lat": 1, "long": 2} then?
Sorry for the train of questions. Please help me obtaining a clear understanding of this. Thanks!
*) https://www.playframework.com/documentation/2.3.x/api/scala/index.html#play.api.libs.json.Writes
UPDATES:
Adding related question: Syntax and meaning of a Scala/Play! code sample
When in doubt, decompile it. This showed that there is an implicit toFunctionalBuilderOps, which then you can see in FunctionalBuilderOps that there is your and method

Why do I get *No Json deserializer found for type Object* when I use getOrElse there?

Using an existing JsValue, I'm parsing its values to fill out a new JSON object.
val json: JsValue = getJson(...)
val newJson: JsObject = Json.obj(
"Name" -> (json \ "personName").asOpt[String].getOrElse("")
)
However, I get the following compile-time error on the third line:
No Json deserializer found for type Object.
Looking at getOrElse's docs, why does "Object," rather than "String," get returned in my above code?
final def getOrElse[B >: A](default: ⇒ B): B
I admit that I don't understand B >: A.