Background
I am trying to use comprehensions with Scala with the Either type, namely using a Right.
However, despite my efforts, I get an error and nothing works.
Code
I am using scala's repl to make a few tests. This is the easiest use case I could come up with:
scala> for {
| x <- Right(1)
| y <- Right(2)
| z <- Right(3)
| } yield x + y + z
You will see it is basically a copy of this page:
https://www.scala-lang.org/api/2.12.7/scala/util/Either.html
Problem
However, this fails with the following error:
<console>:13: error: value flatMap is not a member of scala.util.Right[Nothing,Int]
x <- Right(1)
^
<console>:14: error: value flatMap is not a member of scala.util.Right[Nothing,Int]
y <- Right(2)
^
<console>:15: error: value map is not a member of scala.util.Right[Nothing,Int]
z <- Right(3)
^
I am using using the following version of scala:
Welcome to Scala 2.11.12 (OpenJDK 64-Bit Server VM, Java 11.0.13).
Type in expressions for evaluation. Or try :help.
I understand some changes were made to Either, so it became Right biased, but I don't see how such changes could affect this example.
What am I missing?
In scala 2.11 Either is not a Monad. Combinators like flatMap and map are missing from it. Instead, you call .right or .left to get a RightProjection or LeftProjection which does have the combinators. You need to project your Either as right. The code below will return Right(6).
for {
x <- Right(1).right
y <- Right(2).right
z <- Right(3).right
} yield x + y + z
Related
I'm trying to combine to arrays that are wrapped in an Option:
val a = Option(Array(1, 2, 3))
val b = Option(Array(4,5))
val q = for {
x <- a
y <- b
} yield x ++ y
The problem is that if b is None it returns None even though I'd like to have a. And if a is None the compiler complains that ++ is not a member of Nothing (even though I expect to receive b). Is this doable with the standard library or do I have to look at semigroups in Cats or Scalaz?
I tried the following in Cats but couldn't get it to work:
Semigroup[Option[Array[Int]]].combine(a,b) // === a |+| b
It tells me that:
could not find implicit value for parameter ev: cats.kernel.Semigroup[Option[Array[Int]]]
The resulting type should be the same as the types of a and b.
(a ++ b).flatten.toArray
The ++ method is not a part of the Option class, but it works here because of an implicit conversion. If you see the scala doc for Option, it says This member is added by an implicit conversion from Option[A] to Iterable[A] performed by method option2Iterable in scala.Option.
So, options can be treated as iterables.
Preserving the type Option[C[X]], where C is some collection type and X is the element type of that collection, I came up with:
a.fold(b)(x => b.fold(a)(y => Option(x ++ y)))
You should be able to do
val q = a.toList.flatten ++ b.toList.flatten
I'm currently trying to learn how to use Scala but I'm stuck with some syntax problems.
When I type in the scala prompt:
import scala.collection.immutable._
var q = Queue[Int](1)
println((q+1).toString)
I get the following error:
<console>:12: error: type mismatch;
found : Int(1)
required: String
println((q+1).toString)
I just wanted to use the overloaded + operator of the queue defined as below:
def +[B >: A](elem : B) : Queue[B]
Creates a new queue with element added at the end of the old queue.
Parameters
elem - the element to insert
But it seems that scala does a string concatenation. So, can you help me to understand how to add an element to the queue (without using enqueue which works perfectly; I would like to use the + operator)? And maybe, could you give me some explaination about that behaviour that seems a bit strange for a beginner?
Thank you
You are using the wrong operator (see docs):
scala> var q = Queue[Int](1)
q: scala.collection.immutable.Queue[Int] = Queue(1)
scala> q :+ 2
res1: scala.collection.immutable.Queue[Int] = Queue(1, 2)
scala> 0 +: q
res2: scala.collection.immutable.Queue[Int] = Queue(0, 1)
Since the + operator has no other meaning given those types, Scala defaults to String concatenation, giving you the type mismatch error.
I'm still pretty new to Scala. I'm having trouble trying to append two Sequences together because the compiler is complaining about the type of the Seq. I would like to start with a Seq[String] var and replace it with the addition of two Seq[String]'s. In the REPL session below, we see that y :+ x is a Seq[Object], but why?
Welcome to Scala version 2.11.2 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_71).
Type in expressions to have them evaluated.
Type :help for more information.
scala> val x = Seq[String]("a")
x: Seq[String] = List(a)
scala> var y = Seq[String]("b")
y: Seq[String] = List(b)
scala> y = y :+ x
<console>:9: error: type mismatch;
found : Seq[Object]
required: Seq[String]
y = y :+ x
^
scala> val z = y :+ x
z: Seq[Object] = List(b, List(a))
It's because the :+ operator expects a single item, not a sequence. So what you're trying to do is comparable to var y:List[String] = List("b", List("a")), which isn't valid. You can see this in the documentation of Seq, which shows the type of :+ to be A => Seq[A].
I think you probably want to use the ++ operator instead.
See this:
scala> 1 + 1
res0: Int = 2
scala> 1.+(1)
warning: there were 1 deprecation warning(s); re-run with -deprecation for details
res1: Double = 2.0
scala> "a" :: List()
res2: List[String] = List(a)
scala> "a".::(List())
<console>:8: error: value :: is not a member of String
"a".::(List())
^
Why does the error occur?
Try this
List().::("a")
The reason is that :: is a method of List.
From ScalaByExample:
Like any infix operator, :: is also implemented as a method of an
object. In this case, the object is the list that is extended. This is
possible, because operators ending with a ‘:’ character are treated
specially in Scala. All such operators are treated as methods of their
right operand. E.g.,
x :: y = y.::(x) whereas x + y = x.+(y)
Note, however, that operands of a binary operation are in each case
evaluated from left to right. So, if D and E are expressions with
possible side-effects,
D :: E
is translated to
{val x = D; E.::(x)}
in order to maintain the left-to-right order of operand evaluation.
In scala methods which ends with : got applied in reverse order.
So when you write a::list it is actually list.::(a). String doesn't have :: method, so the solution is to write List().::("a") or Nil.::("a")
Because of operator precedence. In Scala methods which ends with : are right associative. So you should call List().::("a")
If you want to use left associative method then you should write List("a") ++ List(), but that's not always a good choice, cause it has linear execution time
I have just noticed that whilst I need clarifying parens when adding a pair to a map, I don't need them when doing a re-assignment:
Welcome to Scala version 2.9.1.final (Java HotSpot(TM) Server VM, Java 1.6.0_18).
Type in expressions to have them evaluated.
Type :help for more information.
Get me some values
scala> var n = Map.empty[Int, String]
n: scala.collection.immutable.Map[Int,String] = Map()
Trying to add to the map with no clarifying parentheses:
scala> n + 1 -> ""
<console>:30: error: type mismatch;
found : Int(1)
required: (Int, ?)
n + 1 -> ""
^
Fails as I expected it to. But doing the same via a re-assignment does not:
scala> n += 1 -> ""
scala> n
res12: scala.collection.immutable.Map[Int,String] = Map(1 -> "")
What is going on? Why is this not failing? Is scalac adding parens itself?
It's just a precedence issue. + and - have the same precedence. = is lower. So Scala sees (n + 1) -> "" in the former case, and n += (1 -> "") in the latter (which is then transformed to n = (n + (1 -> "")) according to the normal rules for assignment operators.
According to scala reference (6.12.4):
Assignment operators are treated specially in that they can be expanded to assignments if no other interpretation is valid. ... The
re-interpretation occurs if the following two conditions are fulfilled.
1. The left-hand-side l does not have a member named +=, and also cannot be converted by an implicit conversion (§6.26) to a value with a member named > +=.
2. The assignment l = l + r is type-correct. In particular this implies that l refers to a variable or object that can be assigned to, and that is convertible to a value with a member named +.
(1) Immutable Map has no member named += (mutable has) and AFAIK, has no implicit conversions to something with that and assignment is definitely type correct (2): n defined as a variable and has member +.