Why does Scalaz \/ type have getOrElse but not get? - scala

As far as I can tell Scalaz's \/ does not have get method. Sometimes I am sure the value contained in \/ is the right value, and I don't want to use getOrElse. I want to get it directly.
("3".right[Int]) getOrElse("123123123") // 3
if (t.isRight) t.get // compilation error, no get method
How can I get the right value directly, if it is guaranteed.
There are two ways I can get the value, but both look a little bit verbose.
1: change to scala Either
val t = "3".right[Int]
val either = t.toEither
if (either.isRight) either.right.get
else either.left.get
2: Use getOrElse
("3".right[Int]) getOrElse("123123123") // but for some cases I don't have this default value

There is no get as get could throw an exception, which isn't cool. Scalaz enforces this by not allowing direct access to the value.
If you provide more information, we can help out with a solution.
t should be safe.
val safe_thing:T = ???
val either: Throwable \/ T = getFromSomewhere
either getOrElse safe_thing

As other answer pointed out, get could throw. But similarly to OP, I also encountered cases when I was sure of a type (in this case \/-), yet the variable in code was of type \/ (super class).
Doing inline pattern matching was very verbose and looked bad.
println(("test".right[String] |> { case \/-(x) => x; case _ => "" }).toUpperCase)
So I wrote this helper:
implicit class ScalazDisjunctionPimps[A, B](e: \/[A, B]) {
def getRight: B = e match {
case \/-(x) => x
case _ => throw new RuntimeException(s"$e is not right.")
}
}
Usage is simple, here's example:
println("test".right.getRight.toUpperCase) // outputs: TEST
If needed getLeft can be constructed in the same way.

Related

Pattern match on value of Either inside a for comprehension?

I have a for comprehension like this:
for {
(value1: String, value2: String, value3: String) <- getConfigs(args)
// more stuff using those values
}
getConfigs returns an Either[Throwable, (Seq[String], String, String)] and when I try to compile I get this error:
value withFilter is not a member of Either[Throwable,(Seq[String], String, String)]
How can I use this method (that returns an Either) in the for comprehension?
Like this:
for {
tuple <- getConfigs()
} println(tuple)
Joking aside, I think that is an interesting question but it is misnamed a bit.
The problem (see above) is not that for comprehensions are not possible but that pattern matching inside the for comprehension is not possible within Either.
There is documentation how for comprehensions are translated but they don't cover each case. This one is not covered there, as far as I can see. So I looked it up in my instance of "Programming in Scala" -- Second Edition (because that is the one I have by my side on dead trees).
Section 23.4 - Translation of for-expressions
There is a subchapter "Translating patterns in generators", which is what is the problem here, as described above. It lists two cases:
Case One: Tuples
Is exactly our case:
for ((x1, …, xn) <- expr1) yield expr2
should translate to expr1.map { case (x1, …, xn) => expr2).
Which is exactly what IntelliJ does, when you select the code and do an "Desugar for comprehension" action. Yay!
… but that makes it even weirder in my eyes, because the desugared code actually runs without problems.
So this case is the one which is (imho) matching the case, but is not what is happening. At least not what we observed. Hm?!
Case two: Arbitrary patterns
for (pat <- expr1) yield expr2
translates to
expr1 withFilter {
case pat => true
case _ => false
} map {
case pat => expr2
}
where there is now an withFilter method!
This case totally explains the error message and why pattern matching in an Either is not possible.
The chapter ultimately refers to the scala language specification (to an older one though) which is where I stop now.
So I a sorry I can't totally answer that question, but hopefully I could hint enough what is the root of the problem here.
Intuition
So why is Either problematic and doesn't propose an withFilter method, where Try and Option do?
Because filter removes elements from the "container" and probably "all", so we need something that is representing an "empty container".
That is easy for Option, where this is obviously None. Also easy for e.g. List. Not so easy for Try, because there are multiple Failure, each one can hold a specific exception. However there are multiple failures taking this place:
NoSuchElementException and
UnsupportedOperationException
and which is why Try[X] runs, but an Either[Throwable, X] does not.
It's almost the same thing, but not entirely. Try knows that Left are Throwable and the library authors can take advantage out of it.
However on an Either (which is now right biased) the "empty" case is the Left case; which is generic. So the user determines which type it is, so the library authors couldn't pick generic instances for each possible left.
I think this is why Either doesn't provide an withFilter out-of-the-box and why your expression fails.
Btw. the
expr1.map { case (x1, …, xn) => expr2) }
case works, because it throws an MatchError on the calling stack and panics out of the problem which… in itself might be a greater problem.
Oh and for the ones that are brave enough: I didn't use the "Monad" word up until now, because Scala doesn't have a datastructure for it, but for-comprehensions work just without it. But maybe a reference won't hurt: Additive Monads have this "zero" value, which is exactly what Either misses here and what I tried to give some meaning in the "intuition" part.
I guess you want your loop to run only if the value is a Right. If it is a Left, it should not run. This can be achieved really easy:
for {
(value1, value2, value3) <- getConfigs(args).right.toOption
// more stuff using those values
}
Sidenote: I don't know whats your exact use case, but scala.util.Try is better suited for cases where you either have a result or a failure (an exception).
Just write Try { /*some code that may throw an exception*/ } and you'll either have Success(/*the result*/) or a Failure(/*the caught exception*/).
If your getConfigs method returns a Try instead of Either, then your above could would work without any changes.
You can do this using Oleg's better-monadic-for compiler plugin:
build.sbt:
addCompilerPlugin("com.olegpy" %% "better-monadic-for" % "0.2.4")
And then:
object Test {
def getConfigs: Either[Throwable, (String, String, String)] = Right(("a", "b", "c"))
def main(args: Array[String]): Unit = {
val res = for {
(fst, snd, third) <- getConfigs
} yield fst
res.foreach(println)
}
}
Yields:
a
This works because the plugin removes the unnecessary withFilter and unchecked while desugaring and uses a .map call. Thus, we get:
val res: Either[Throwable, String] =
getConfigs
.map[String](((x$1: (String, String, String)) => x$1 match {
case (_1: String, _2: String, _3: String)
(String, String, String)((fst # _), (snd # _), (third # _)) => fst
}));
I think the part you may find surprising is that the Scala compiler emits this error because you deconstruct the tuple in place. This is surprisingly forces the compiler to check for withFilter method because it looks to the compilers like an implicit check for the type of the value inside the container and checks on values are implemented using withFilter. If you write your code as
for {
tmp <- getConfigs(args)
(value1: Seq[String], value2: String, value3: String) = tmp
// more stuff using those values
}
it should compile without errors.

Why does creating a map function whose parameter is of type `Nothing => U` appear to work?

I'm writing Scala code that uses an API where calls to the API can either succeed, fail, or return an exception. I'm trying to make an ApiCallResult monad to represent this, and I'm trying to make use of the Nothing type so that the failure and exception cases can be treated as a subtype of any ApiCallResult type, similar to None or Nil. What I have so far appears to work, but my use of Nothing in the map and flatMap functions has me confused. Here's a simplified example of what I have with just the map implementation:
sealed trait ApiCallResult[+T] {
def map[U]( f: T => U ): ApiCallResult[U]
}
case class ResponseException(exception: APICallExceptionReturn) extends ApiCallResult[Nothing] {
override def map[U]( f: Nothing => U ) = this
}
case object ResponseFailure extends ApiCallResult[Nothing] {
override def map[U]( f: Nothing => U ) = ResponseFailure
}
case class ResponseSuccess[T](payload: T) extends ApiCallResult[T] {
override def map[U]( f: T => U ) = ResponseSuccess( f(payload) )
}
val s: ApiCallResult[String] = ResponseSuccess("foo")
s.map( _.size ) // evaluates to ResponseSuccess(3)
val t: ApiCallResult[String] = ResponseFailure
t.map( _.size ) // evaluates to ResponseFailure
So it appears to work the way I intended with map operating on successful results but passing failures and exceptions along unchanged. However using Nothing as the type of an input parameter makes no sense to me since there is no instance of the Nothing type. The _.size function in the example has type String => Int, how can that be safely passed to something that expects Nothing => U? What's really going on here?
I also notice that the Scala standard library avoids this issue when implementing None by letting it inherit the map function from Option. This only furthers my sense that I'm somehow doing something horribly wrong.
Three things are aligning to make this happen, all having to do with covariance and contravariance in the face of a bottom type:
Nothing is the bottom type for all types, e.g. every type is its super.
The type signature of Function1[-T, +R], meaning it accepts any type which is a super of T and returns any type for which R is a super.
The type ApiCallResult[+R] means any type U for which R is a super of U is valid.
So any type is a super of Nothing means both any argument type is valid and the fact that you return something typed around Nothing is a valid return type.
I suggest that you don't need to distinguish failures and exceptions most of the time.
type ApiCallResult[+T] = Try[T]
case class ApiFailure() extends Throwable
val s: ApiCallResult[String] = Success("this is a string")
s.map(_.size)
val t: ApiCallResult[String] = Failure(new ApiFailure)
t.map(_.size)
To pick up the failure, use a match to select the result:
t match {
case Success(s) =>
case Failure(af: ApiFailure) =>
case Failure(x) =>
}

Casting error from Option[Double] to Double in scala

I am facing a problem in casting from Option[Double] to Double. I am getting the following exception error:
scala.Some cannot be cast to java.lang.Double
val ty = ttnew.distinct().leftOuterJoin(rank).map{ case ((key),(c,d)) => (key,c._1,c._2,c._3,d.getOrElse(Double).asInstanceOf[Double]) }
Please Help!
d.getOrElse(Double).asInstanceOf[Double]
makes no sense.
Assuming d is an Option[Double] if you want to have a Double you cannot cast it, you need to get the value "out of" the Option.
getOrElse allows you to get the value if present, and provide a fallback value if absent (i.e. None).
For example:
d.getOrElse(0) // 0, or anything that makes sense as a fallback
If d has type Option[Double] then d.getOrElse(0) has type Double.
that's not how you deal with Option. Use .getOrElse or a .map
val ty=ttnew.distinct().leftOuterJoin(rank).map{ case ((key),(c,d)) => (key,c._1,c._2,c._3,d.getOrElse(Double).asInstanceOf[Double]) }
probably (in this situation) you will want to do d.getOrElse(<a-good-default-value-like-zero-maybe>)
other situations maybe you want to propagate the meaning of Option (the value may not exist), and in those cases you should use the .map:
val res: Option[String] = optionalDouble.map(doubleValue => callSomeFunctionThatConvertsDoubleToString(value))
you can even do other things using pattern matching and extractors. for instance, using .collect (it's a .map, but there may be cases not covered):
val ty=ttnew.distinct().leftOuterJoin(rank).collect{ case ((key),(c,Some(d))) => (key,c._1,c._2,c._3,d) }

Is this scala function to heavy/doing too many things to unit test properly?

OK, so I am looking at testing libraries, in particular ScalaTest & ScalaMock.
I wanted to write a test to test this function that I have written:
def gameMenuSelect(): State = {
Try(UI.readOption) match {
case Success(i) => {
i match {
case 1 => HumanGame
case 2 => MachineGame
case 3 => sys.exit(0)
case _ =>
UI.invalidSelectionMsg
ChoosingGame
}
}
case Failure(e) => UI.invalidSelectionMsg; ChoosingGame
}
}
A bit of background, UI.readOption is a simple scala.io.StdIn.readInt.
State is a Trait - subsequently HumanGame, MachineGame and ChoosingGame are also Traits that extend State.
The problem is I have no idea how I would test it, the reason is because I feel like this function does too much.
It is reading input, validating that the input given is indeed a number/integer and not throwing a NumberFormatException. Given that the input is an integer it is match on allowable integers.
I really feel like there is a lot to test, also a lot that I am not sure is unit testable.
Could I have some opinions on whether you feel that this function is doing too many things, whether I should try to break up the reading of the integer and the matching of it?
Thanks.
Yes, should absolutely try to separate the "side-effecting" bits, reading and writing, from the selection logic. The selection logic can return something like
import scalaz._, Scalaz._
def selectGame(i: Int): GameError \/ State =
i match {
case 1 => HumanGame.right
case 2 => MachineGame.right
case _ => InvalidGame(i).left
}
sealed trait GameError
case class InvalidGame(i: Int) extends GameError
object GameError {
def render(e: GameError): String =
e match {
case InvalidGame(i) =>
s"Invalid game choice: $i. Only 1 and 2 are acceptable values"
}
}
Note that I also model the error into a specific type instead of just using strings.
Then you can do the same with your number parsing:
def parseInt(i: String): ParseError \/ Int =
???
For your "effects" you can use Scalaz IO for the interactions with the console:
def readLine: IO[String] =
IO(StdIn.readLine)
def printLine(line: String): IO[Unit] =
IO(println(line))
Then, with a bit more code, you can use the EitherT[IO, E, A] monad to "assemble" all your functions:
// I will provide a full example if you want to go this way
val actions: EitherT[IO, ApplicationError, Unit] =
for {
line <- readLine
i <- parseInt(line)
s <- selectGame(i)
_ <- printLine(s.render)
} yield ()
The actions value will both have IO side-effects and collect errors, stopping the process if there are any.
Eventually this all makes your testing a lot easier because you have isolated the "pure" parts which are way easier to test: no setup, no mocks, just pure functions.
In my opinion, there are too many side effects in your function. Not only the reading of the integer, but also sys.exit(0). You could change the method to accept the integer as a parameter, and also add an EndingGame state that you could use for case 3. You would then have a pure function that is easily testable.

Using unapply as constructor in match

Is it good style in Scala to "abuse" the unapply method for pattern matching? What I wanted to do, is matching an object against another, and constructing the other object. Since I am fairly new in Scala, I wound up with the following solution. But it doesnt seem really right to use the unapply methode like this, since it is intended as an extractor. Could someone please give me feedback on this?
object Poker {
def unapply(hand: Hand): Option[Poker] = if(hand.countValueGroups().exists(_._2 == 4)) Some(new Poker(hand)) else None
}
val h = Hand("AC As AH Ad 2h")
h match {
case Poker(han) => println("POKER!!!"+han)
case _ => println("?????")
}
I don't know why this should be bad practice, so I'd say the answer is no, this is normal practice. As one commenter said, the mere purpose of unapply is to be used in pattern matching. While pattern matching is mostly used with the companion object of a case class, the concept is deliberately open to other extractors (example: regular expressions).
The only thing that's weird in your example is to return Option[Poker] with Poker begin a singleton object. Since you can't do much with that, probably you want to use a Boolean instead:
object Poker {
def unapply(hand: Hand): Boolean =
hand.countValueGroups().exists(_._2 == 4)
}
case class Hand(s: String) {
def countValueGroups(): List[(Any, Int)] = List("foo" -> 4) // ???
}
val h = Hand("AC As AH Ad 2h")
h match {
case Poker() => println("POKER!!!")
case _ => println("?????")
}