Scala implicit for Option containing Map - scala

I am trying to write the following implicit:
implicit class ExtractOrElse[K, V](o: Option[Map[K, V]]) {
def extractOrElse(key: K)(f: => V): V = { if (o.isDefined) o.get(key) else f }
}
Which I want to use in this way:
normalizationContexts.extractOrElse(shardId)(defaultNormalizationContext)
to avoid a clunkier syntax (normalizationContexts is an Option[Map[String, NormzalitionContext]]).
Also, let me add that it is intentional that there is only one default value: it will be used if the Option isEmpty, but if the Option isDefined, then the behavior of the Map is not changed, and it will throw an exception if the key is not found - so the default value won't be used in that case, and this is all intentional.
However, I get an error when passing in None in unit tests:
assertEquals(None.extractOrElse('a')(0), 0)
results in:
Error:(165, 37) type mismatch;
found : Char('a')
required: K
assertEquals(None.extractOrElse('a')(0), 0)
I realize that None is not parametric, as it is defined as:
case object None extends Option[Nothing] {
def isEmpty = true
def get = throw new NoSuchElementException("None.get")
What is the best way to make this work?

Instead of None.extractOrElse(...), try Option.empty[Map[Char, Int]].extractOrElse(...).
If you always use the same types for your test cases, you could also create a type alias in the specs class in order to reduce the clutter:
type OpMap = Option[Map[Char, Int]]
// ...
assertEquals(Option.empty[OpMap].extractOrElse('a')(0), 0)
Just in case, you can use flatMap and getOrElse to achieve the same thing without writing a new method:
val n = Option.empty[Map[String, Int]]
val s = Some(Map("x" → 1, "y" → 2))
n.flatMap(_.get("x")).getOrElse(3) // 3
s.flatMap(_.get("x")).getOrElse(3) // 1
s.flatMap(_.get("z")).getOrElse(3) // 3

The type system doesn't have enough information about the types K and V. There is no way to know what the type of A would be in the case where your None was Some[A].
When I create an example with explicit types, the code works as expected:
// Like this
val e = new ExtractOrElse(Option.empty[Map[Char, Int]])
e.extractOrElse('a')(0) // Equals 0
// Or like this
val e = new ExtractOrElse[Char, Int](None)
println(e.extractOrElse('a')(0))
// Or like this
val m: Option[Map[Char, Int]] = None
val e = new ExtractOrElse(m)
println(e.extractOrElse('a')(0))

Related

Syntactic sugar explanation of Scala'a unapply method

I am getting an error in the extractor step (unapply method call).
The error message is: Wrong number of arguments for the extractors. found 2; expected 0
Can someone please help what is causing the error (where my misunderstanding is).
class ABC(val name:String, val age:Int) //class is defined.
object ABC{
def apply(age:Int, name:String) = new ABC(name, age)
def unapply(x:ABC) = (x.name, x.age)
}
val ins = ABC(25, "Joe") //here apply method is in action.
val ABC(x,y) = ins //unapply is indirectly called. As per my understanding , 25 and Joe suppose to be captured in x and y respectively. But this steps gives error.
The error I get is
an unapply result must have a member def isEmpty: Boolean
The easiest way to fix this is to make unapply return an Option:
def unapply(x: ABC) = Option((x.name, x.age))
The unapply method in an extractor which binds values must return an Option. This is because there's no intrinsic guarantee that an extractor will always succeed. For instance consider this massively oversimplified example of an extractor for an email address:
object Email {
def unapply(s: String): Option[(String, String)] =
s.indexOf('#') match {
case idx if idx >= 0 =>
val (user, maybeSite) = s.splitAt(idx)
if (maybeSite.length < 2 || maybeSite.lastIndexOf('#') > 0) None
else Some(user -> maybeSite.tail)
case _ => None
}
}
At the application site:
val Email(u, s) = "user3103957#stackoverflow.example.xyz"
Turns into code that's basically (from the description in Programming In Scala (Odersky, Spoon, Venners (3rd ed))):
val _tmpTuple2 =
"user3103957#stackoverflow.example.xyz" match {
case str: String =>
Email.unapply(str).getOrElse(throw ???)
case _ => throw ???
}
val u = _tmpTuple2._1
val s = _tmpTuple2._2
Technically, since the compiler already knows that the value is a String, the type check is elided, but I've included the type check for generality. The desugaring of extractors in a pattern match also need not throw except for the last extractor attempt.

Scala: Creating Options from Seq/Tuple and add to a Sequence

Edit:
Suppose I have a Seq:
Seq(Some("Earth"),Some("Mars"))
I need to add few more elements at start of this sequence. Values to be added are generated based on an Option value.
So I try to do as:
val o = ....//Option calculated here
Seq(o.map(myFunction(_)),"Earth","Mars")
def myFunction(s: String) = s match {
case "x" => Seq(Some("Jupiter"), Some("Venus"))
case "y" => Seq(Some("PLuto"), Some("Mercury"))
}
But map would give me Some(Seq(.....)).
For this kind of problem I recommend checking the Scaladoc and following a technique called type-tetris.
You need this:
def prependIfDefined(data: Option[A], previousElements: Seq[Option[B]]): Seq[Option[B]] =
data.fold(ifEmpty = Seq.empty[Option[B]])(getNewData) ++ previousElements
def getNewData(a: A): Seq[Option[B]] = ???

Convert Seq[Try[Option(String, Any)]] into Try[Option[Map[String, Any]]]

How to conveniently convert Seq[Try[Option[String, Any]]] into Try[Option[Map[String, Any]]].
If any Try before convert throws an exception, the converted Try should throw as well.
Assuming that the input type has a tuple inside the Option then this should give you the result you want:
val in: Seq[Try[Option[(String, Any)]]] = ???
val out: Try[Option[Map[String,Any]]] = Try(Some(in.flatMap(_.get).toMap))
If any of the Trys is Failure then the outer Try will catch the exception raised by the get and return Failure
The Some is there to give the correct return type
The get extracts the Option from the Try (or raises an exception)
Using flatMap rather than map removes the Option wrapper, keeping all Some values and discaring None values, giving Seq[(String, Any)]
The toMap call converts the Seq to a Map
Here is something that's not very clean but may help get you started. It assumes Option[(String,Any)], returns the first Failure if there are any in the input Seq and just drops None elements.
foo.scala
package foo
import scala.util.{Try,Success,Failure}
object foo {
val x0 = Seq[Try[Option[(String, Any)]]]()
val x1 = Seq[Try[Option[(String, Any)]]](Success(Some(("A",1))), Success(None))
val x2 = Seq[Try[Option[(String, Any)]]](Success(Some(("A",1))), Success(Some(("B","two"))))
val x3 = Seq[Try[Option[(String, Any)]]](Success(Some(("A",1))), Success(Some(("B","two"))), Failure(new Exception("bad")))
def f(x: Seq[Try[Option[(String, Any)]]]) =
x.find( _.isFailure ).getOrElse( Success(Some(x.map( _.get ).filterNot( _.isEmpty ).map( _.get ).toMap)) )
}
Example session
bash-3.2$ scalac foo.scala
bash-3.2$ scala -classpath .
Welcome to Scala 2.13.1 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_66).
Type in expressions for evaluation. Or try :help.
scala> import foo.foo._
import foo.foo._
scala> f(x0)
res0: scala.util.Try[Option[Equals]] = Success(Some(Map()))
scala> f(x1)
res1: scala.util.Try[Option[Equals]] = Success(Some(Map(A -> 1)))
scala> f(x2)
res2: scala.util.Try[Option[Equals]] = Success(Some(Map(A -> 1, B -> two)))
scala> f(x3)
res3: scala.util.Try[Option[Equals]] = Failure(java.lang.Exception: bad)
scala> :quit
If you're willing to use a functional support library like Cats then there are two tricks that can help this along:
Many things like List and Try are traversable, which means that (if Cats's implicits are in scope) they have a sequence method that can swap two types, for example converting List[Try[T]] to Try[List[T]] (failing if any of the items in the list are failure).
Almost all of the container types support a map method that can operate on the contents of a container, so if you have a function from A to B then map can convert a Try[A] to a Try[B]. (In Cats language they are functors but the container-like types in the standard library generally have map already.)
Cats doesn't directly support Seq, so this answer is mostly in terms of List instead.
Given that type signature, you can iteratively sequence the item you have to in effect push the list type down one level in the type chain, then map over that container to work on its contents. That can look like:
import cats.implicits._
import scala.util._
def convert(listTryOptionPair: List[Try[Option[(String, Any)]]]): Try[
Option[Map[String, Any]]
] = {
val tryListOptionPair = listTryOptionPair.sequence
tryListOptionPair.map { listOptionPair =>
val optionListPair = listOptionPair.sequence
optionListPair.map { listPair =>
Map.from(listPair)
}
}
}
https://scastie.scala-lang.org/xbQ8ZbkoRSCXGDJX0PgJAQ has a slightly more complete example.
One way to approach this is by using a foldLeft:
// Let's say this is the object you're trying to convert
val seq: Seq[Try[Option[(String, Any)]]] = ???
seq.foldLeft(Try(Option(Map.empty[String, Any]))) {
case (acc, e) =>
for {
accOption <- acc
elemOption <- e
} yield elemOption match {
case Some(value) => accOption.map(_ + value)
case None => accOption
}
}
You start off with en empty Map. You then use a for comprehension to go through the current map and element and finally you add a new tuple in the map if present.
The following solutions is based on this answer to the point that almost makes the question a duplicate.
Method 1: Using recursion
def trySeqToMap1[X,Y](trySeq : Seq[Try[Option[(X, Y)]]]) : Try[Option[Map[X,Y]]] = {
def helper(it : Iterator[Try[Option[(X,Y)]]], m : Map[X,Y] = Map()) : Try[Option[Map[X,Y]]] = {
if(it.hasNext) {
val x = it.next()
if(x.isFailure)
Failure(x.failed.get)
else if(x.get.isDefined)
helper(it, m + (x.get.get._1-> x.get.get._2))
else
helper(it, m)
} else Success(Some(m))
}
helper(trySeq.iterator)
}
Method 2: directly pattern matching in case you are able to get a stream or a List instead:
def trySeqToMap2[X,Y](trySeq : LazyList[Try[Option[(X, Y)]]], m : Map[X,Y]= Map.empty[X,Y]) : Try[Option[Map[X,Y]]] =
trySeq match {
case Success(Some(h)) #:: tail => trySeqToMap2(tail, m + (h._1 -> h._2))
case Success(None) #:: tail => tail => trySeqToMap2(tail, m)
case Failure(f) #:: _ => Failure(f)
case _ => Success(Some(m))
}
note: this answer was previously using different method signatures. It has been updated to conform to the signature given in the question.

Restore a dependent type at runtime

I'm trying to restore a dependent type in Scala at runtime. I basically want to archive a type-save map, where every key has an associated type, but all type informations of the stored key value pairs aren't visible to the user of Map (unlike the awesome Shapeless Map).
class Key[V] {
type Value = V
def ->(value: V) = Pair(this, value)
}
trait Pair {
val key: Key[_]
val value: key.Value
}
trait Map {
val pairs: Seq[Pair]
def get[V](key: Key[V]): Option[V] =
pairs.find(pair => pair.key eq key).map(_.value).asInstanceOf[Option[V]]
// ^ ^
// the runtime prove that pair.key.Value equals V |
// |
// 'Convince' the compile that I know what I do
}
Usage:
val text = new Key[String]
val count = new Key[Int]
val map: Map = new Map { val pairs = text -> "Hello World!" :: Nil }
map.get(text) // Some(Hello World!), Type: Option[String]
map.get(count) // None, Type: Option[Int]
Is it possible to write a get method without using a cast explicit with asInstanceOf or implicit with a match with an unchecked branch?
I tried to write an unapply for pairs, but run into the same problem.
Note that I leave out the definition of the Pair-companion object. Here a running example in a Gist.
Remember the JVM erases generics at runtime. So anything that relies on generics, including dependent typing, can only happen at compile time - i.e. in the caller, because any given method will only compile to one runtime code path. The only alternative is checking the runtime class (either directly or by pattern matching) as you say. (Shapeless has a type-safe, typeclass-driven helper if you go down that route)
There might be a clever way to express your requirements without the type issues, but in general the type information has to be either visible to the caller or checked at runtime.
Many way to solve your type issue. First of all define source of issue:
trait Map {
val pairs: Seq[Pair] // (1)
def get[V](key: Key[V]): Option[V] = // (2)
pairs.find(_.key eq key).map{_.value } // (3)
}
pairs type is Seq of Pair (with some embedded undefined type key: Key[_])
key type is Key[V] and expected result type is Option[V]
try to return type from (1) Key[_] instead of expected Key[V] and extracted V
Solution: you should guaranty that pairs embedded type of key is the same what you return
One of possible solutions:
trait Key[V] {
def ->(value: V) = Pair(this, value)
}
trait Pair {
type Value
val key: Key[Value]
val value: Value
}
trait Map1[V] {
val pairs: Seq[Pair {type Value = V } ]
def get(key: Key[V]): Option[V] =
pairs.find(_.key eq key).map{ _.value }
}
trait Map2 {
type Value
val pairs: Seq[Pair {type Value = Map2.this.Value} ]
def get[V >: Map2.this.Value](key: Key[V]): Option[V] =
pairs.find(_.key eq key).map{ _.value }
}

Acquiring 2 implicits for scalacheck function

I am using scalacheck and am in the middle of a generic-programming soup right now. The official guide shows this example:
def matrix[T](g: Gen[T]): Gen[Seq[Seq[T]]] = Gen.sized { size =>
val side = scala.math.sqrt(size).asInstanceOf[Int]
Gen.listOfN(side, Gen.listOfN(side, g))
}
Meanwhile, for my test I require a matrix of type Array[Array[T]]. I tried with the following function:
def matrix[T](g: Gen[T]): Gen[Array[Array[T]]] = Gen.sized { size =>
val side = scala.math.sqrt(size).asInstanceOf[Int]
val g1 = Gen.containerOfN[Array, T](side, g)
Gen.containerOfN[Array, Array[T]](side, g1)
}
Here, I run into trouble. The compiler says:
Multiple markers at this line
- not enough arguments for method containerOfN: (implicit b: org.scalacheck.util.Buildable[T,Array])org.scalacheck.Gen[Array[T]].
Unspecified value parameter b.
- could not find implicit value for parameter b: org.scalacheck.util.Buildable[T,Array]
- could not find implicit value for parameter b: org.scalacheck.util.Buildable[T,Array]
- not enough arguments for method containerOfN: (implicit b: org.scalacheck.util.Buildable[T,Array])org.scalacheck.Gen[Array[T]].
Unspecified value parameter b.
I understand that stuff like this is usually remedied by adding implicit parameters to the function, however, i havent made this work yet.
I usually encounter this error when building generic arrays, as an example:
def build[T](n:Int)(implicit m:ClassManifest[T]) = Array.ofDim[T](n)
but, I am afraid I don't fully understand what is happening or why this is needed.
Can someone explain how to make the correct matrix-function along with an example of usage in scalacheck? A thorough explanation of the details about building sequences with implicit class manifests would be very welcome!
edit
import org.scalacheck.util.Buildable._
def matrix[T](g: Gen[T])(implicit b: Buildable[T, Array]): Gen[Array[Array[T]]] = Gen.sized { size =>
val side = scala.math.sqrt(size).asInstanceOf[Int]
val g1 = Gen.containerOfN[Array, T](side, g)
Gen.containerOfN[Array, Array[T]](side, g1)
}
Still doesn't work. Need implicit for Buildable[Array[T],Array]... Don't know how to get this because I can only add 1 implicit argument :/
You're almost there. The important part of the error is could not find implicit value for parameter b: org.scalacheck.util.Buildable[T,Array]
Looking at the method definition of containerOfN
def containerOfN[C[_],T](n: Int, g: Gen[T])(implicit b: Buildable[T,C]): Gen[C[T]] = ...
So, there's your missing argument. You need an implicit argument of type Buildable[T,Array]. Following through to where Buildable is defined in the scalacheck sources, I found that there was an object (org.scalacheck.util.Buildable) that provides implicits that provide Buildables for the common collection types which includes Array. So all you need to bring that into scope. You can do this with:
import org.scalacheck.util.Buildable._
def matrix[T](g: Gen[T]): Gen[Array[Array[T]]] = Gen.sized { size =>
val bT = implicitly[Buildable[T, Array]]
val bArrayT = implicitly[Buildable[Array[T], Array]]
val side = scala.math.sqrt(size).asInstanceOf[Int]
val g1 = Gen.containerOfN[Array, T](side, g)
Gen.containerOfN[Array, Array[T]](side, g1)
}
Or
import org.scalacheck.util.Buildable._
def matrix[T](g: Gen[T])(implicit bT: Buildable[T, Array], bArrayT: Buildable[Array[T], Array]): Gen[Array[Array[T]]] = Gen.sized { size =>
...
}
The particular implicit you need in org.scalacheck.util.Buildable is:
implicit def buildableArray[T](implicit cm: ClassManifest[T]) =
new Buildable[T,Array] {
def builder = mutable.ArrayBuilder.make[T]
}