Suppose I have following code:
val either: Either[String, (Int, Int)] = Right((1,2))
for {
(a, b) <- either.right
} yield a + b
When I evaluate it in REPL I get
:13: error: constructor cannot be instantiated to expected
type; found : (T1, T2) required:
scala.util.Either[Nothing,(Double, Double)]
(a, b) <- a.right
^ :14: error: not found: value a
} yield a + b
^
Why do I have such error? Can't I pattern match on tuple from Either's Right?
Issue seems to be a scala bug https://issues.scala-lang.org/browse/SI-7222. Converting the for comprehension to flatMap/map notation seems to work.
val either: Either[String, (Int, Int)] = Right((1, 2))
either.right.map {
case (a, b) =>
a + b
}
either: Either[String,(Int, Int)] = Right((1,2))
res0: Serializable with Product with scala.util.Either[String,Int] = Right(3)
Related
I have the following code snippet which can not be compiled:
val cids = List(1, 2, 3, 4)
val b = Map.newBuilder[Int, Int]
for (c <- cids) {
b += (c, c*2)
}
b.result()
Compiler reports that
console>:11: error: type mismatch;
found : Int
required: (Int, Int)
b += (c, c*2)
I have no idea what's the mistake.
This would work:
for (c <- cids) {
b += ((c, c*2))
}
The parenthesis are parsed by compiler as the argument-list parenthesis of the += function, and not as a tuple. Adding nested parenthesis means a tuple is passed as the argument. It is confusing...
You can fix it the following way:
b += (c->c*2)
This is a duplicate question.
Normally, supplying an untupled arg list works as shown, but it doesn't work when the method is overloaded, because it will choose the method you didn't intend, and not bother to try auto-tupling your args.
scala> class C[A] { def f(a: A) = 42 }
defined class C
scala> val c = new C[(String, Int)]
c: C[(String, Int)] = C#3a022576
scala> c.f("1", 1)
res0: Int = 42
scala> class C[A] { def f(a: A) = 42 ; def f(a: A, b: A, rest: A*) = 17 }
defined class C
scala> val c = new C[(String, Int)]
c: C[(String, Int)] = C#f9cab00
scala> c.f("1", 1)
<console>:14: error: type mismatch;
found : String("1")
required: (String, Int)
c.f("1", 1)
^
An approach using (immutable) values,
(cids zip cids.map(_ * 2)).toMap
Using zip we pair each value with its double, and the resulting list is converted to a Map.
If you go to the documentation you will find : this
The supported API is ms += (k -> v) . That is you need to use
for (c <- cids) {
b += (c -> c*2)
}
Alternately you could use the ((c, c*2)) syntax as suggested above. This is happening because the compiler has no way of knowing that the parentheses are for the tuple. It simply understands that argument as two parameters being passed to the += method.
Given:
scala> val x: Either[Boolean, (Int, Int)] = Right( (5, 10) )
x: Either[Boolean,(Int, Int)] = Right((5,10))
I'd like to pattern match on the first and second tuple values in x.right, but this didn't work:
scala> for {
| (a, b) <- x.right
| } yield a
<console>:14: error: constructor cannot be instantiated to expected type;
found : (T1, T2)
required: scala.util.Either[Nothing,(Int, Int)]
(a, b) <- x.right
^
I can do something like:
scala> for { a <- x.right } yield a match { case (x, y) => x }
res5: scala.util.Either[Boolean,Int] = Right(5)
But, is there any way for me to change my first, non-compiling code to work?
This is a known bug. See SI-7222.
For now, if you're going to rely on RightProjection, you'll have to match the entire tuple, and use the _1 and _2 accessors.
You could also use a right-biased Either such as scalaz.\/, though that would require Monoid[Boolean] in this example.
If:
scala> val l = List() // List() same as List[Nothing]()
l: List[Nothing] = List()
scala> 1 :: l
res0: List[Int] = List(1)
or:
scala> 1 :: List[Nothing]()
res6: List[Int] = List(1)
Why then this does not work out:
scala> List(1,2,3). foldLeft( List() ) ((acc,x) => x :: acc)
So I have to type this explicitly List[Int]():
scala> List(1,2,3). foldLeft( List[Int]() ) ((acc,x) => x :: acc)
res3: List[Int] = List(3, 2, 1)
?
Though it does in Haskell, for example:
foldl (\acc x -> x:acc) [] [1,2,3]
Let's look at scala's foldLeft signature:
List[+A].foldLeft[B](z: B)(f: (B, A) ⇒ B): B
and haskell's signature:
foldl :: (b -> a -> b) -> b -> [a] -> b
They pretty much same, but:
1) scala has problem with type inference between [pseudo-]curried parameter lists, just compare:
scala> def aaa[A](a: A)(b: A) = {}
aaa: [A](a: A)(b: A)Unit
scala> aaa(null: Any)(5)
scala> aaa(5)(null: Any)
<console>:21: error: type mismatch;
found : Any
required: Int
aaa(5)(null: Any)
^
So scala can choose bigger type from left to right only.
More than that, this is a problem only for [pseudo-]curried functions:
scala> def aaa[T](a: T, b: T) = a
aaa: [T](a: T, b: T)T
scala> aaa(List("a"), List(6.0))
res26: List[Any] = List(a)
scala> aaa(List(6.0), List("a"))
res27: List[Any] = List(6.0)
Here scala not only picked a bigger type - it found a common supertype of both T's. So, it's trying to choose bigger type (if it's in the left part) by default, but looking for a common supertype inside one parameter list.
Note: I'm talking about [pseudo-] currying, as method with multiple parameter lists (B)((B, A) => B)B becoming curried function only after eta-expansion: foldLeft _ gives B => (B,A) => B
2) haskell uses "object" of List itself as function's parameter, which allows you to do even:
Prelude> let f = foldl (\acc x -> x:acc) []
:: [a] -> [a] //here is the polymorphic function
Prelude> f [1,2,3]
[3,2,1]
Prelude> f ["1","2","3"]
["3","2","1"]
In scala you need:
scala> def f[T](x: List[T]) = x.foldLeft(List[T]()) ((acc,x) => x :: acc)
f: [T](x: List[T])List[T]
scala> f(List(1,2,3))
res3: List[Int] = List(3, 2, 1)
scala> f(List("1","2","3"))
res3: List[String] = List(3, 2, 1)
3) Finally, let's rewrite foldLeft and place monoid's 'add' and 'identity' to the same parameter list (to avoid separate inference from p.1):
def foldLeft[T, U](l: List[T])(identity: U, add: (U,T) => U) = l.foldLeft(identity)(add)
and define polymorphic add operation:
scala> def add[A](x: List[A], y: A) = y :: x
add: [A](x: List[A], y: A)List[A]
So you can:
scala> foldLeft(List(1,2,3))(Nil, add)
res63: List[Int] = List(3, 2, 1)
in comparision with:
scala> List(1,2,3).foldLeft(Nil)(add)
<console>:9: error: polymorphic expression cannot be instantiated to expected type;
found : [A, B](x: List[A], y: A)List[A]
required: (scala.collection.immutable.Nil.type, Int) => scala.collection.immutable.Nil.type
List(1,2,3).foldLeft(Nil)(add)
^
Unfortunately, scala can't infer generic type for lambdas, so you can't:
scala> foldLeft(List(1,2,3))(Nil, (acc,x) => x :: acc)
<console>:10: error: missing parameter type
foldLeft(List(1,2,3))(Nil, (acc,x) => x :: acc)
as you can't:
scala> val a = (acc,x) => x :: acc
<console>:7: error: missing parameter type
val a = (acc,x) => x :: acc
^
2 & 3) Because scala has no polymorphic lambdas at all. Can't infer A => List[A] => A (where A is a type parameter) from (acc,x) => x :: acc (even A => A from val a = (a) => a), but Haskell can:
Prelude> let lambda = \acc x -> x:acc
:: [a] -> a -> [a]
Prelude> let f = foldl(lambda) []
Prelude> f [1,2,3]
[3,2,1]
Here is an eta-expansion of perviously defined add generic method in scala:
scala> add _
res2: (List[Nothing], Nothing) => List[Nothing] = <function2>
def foldLeft[B](z: B)(f: (B, A) => B): B
Nothing is a sub-type of every other type, in this case Int. Since List() is inferred to have type List[Nothing], then f is expected to be (List[Nothing], A) => List[Nothing]
But in the function (acc, x) => x :: acc) , A is an Int, which means you should have:
(List[Nothing], Int) => List[Nothing]
When really you have:
(List[Nothing], Int) => List[Int]
And thus the type mismatch, because List[Int] can't be a List[Nothing].
This is similar to:
class A
class B extends A
scala> List.fill(5)(new A).foldLeft(List.empty[B])((acc, x) => x :: acc)
<console>:10: error: type mismatch;
found : A
required: B
List.fill(5)(new A).foldLeft(List.empty[B])((acc, x) => x :: acc)
^
can someone explain the best way to get around the following,
rather curious type error. Suppose I create a list of tuples like so:
scala> val ys = List((1,2), (3,4), (5,6))
ys: List[(Int, Int)] = List((1,2), (3,4), (5,6))
Now, if I want to map this to a List(Int)
scala> ys.map((a: Int, b: Int) => a + b)
<console>:9: error: type mismatch;
found : (Int, Int) => Int
required: ((Int, Int)) => ?
ys.map((a: Int, b: Int) => a + b)
^
Any clues? I know I can use the for comprehension
scala> for ((a, b) <- ys) yield a + b
res1: List[Int] = List(3, 7, 11)
But it feels wrong to bust out a comprehension in this setting. Thanks!
try:
ys.map { case (a: Int, b: Int) => a + b }
or:
ys.map(p: (Int, Int) => p._1 + p._2)
What's happening is that ys is a List of (Int,Int), so map expects a function from a single argument, which happens to be a tuple (Int,Int), to something else (technically, map expects an argument of Function1[(Int,Int),Int]. The function (a: Int, b: Int) => a+b is not actually a function from a single argument (Int, Int) to Int; instead it's a function of two arguments, both Ints, to an Int (a Function2[Int,Int,Int]). The difference is subtle, but important since Scala makes a distinction:
val f: Function1[(Int,Int),Int] = (p: (Int,Int)) => p._1 + p._2
ys.map(f) // fine
val g: Function1[(Int,Int),Int] = { case (a: Int, b: Int) => a + b }
ys.map(g) // fine, technically a PartialFunction[(Int,Int),Int]
val h: Function2[Int,Int,Int] = (a: Int, b: Int) => a + b
ys.map(h) // ERROR!
To explain my suggestions at the top of the answer: In the first example, we have changed the definition of the function given to map to use case, which tells Scala to unpack the single (Int,Int) argument into its two parts. (Note also the use of curly braces instead of parentheses.) In the second example, we have a function of a single tuple argument, p, and we manually extract each part of the tuple.
Finally, note that you don't need the type annotations either. These work just as well:
ys.map { case (a,b) => a + b }
ys.map(p => p._1 + p._2)
try:
val ys = List((1,2),(3,4),(5,6))
ys map (t => t._1 + t._2)
I am trying to get a simple piece of functionality to work where I have a List of Lists and I want to do some mathematical operations on the data (-, + , *, /). I want the method to take any of the following types (Int, Float, Double).
here is what I have tried:
def doSomething[T](data: List[T]){
data reduceLeft(_ / _)
}
the following is displayed: value / is not a member of type parameter T.
How do I get this to work for the AnyVal types (Double, Int, Float)?
Update I tried implementing the suggestion in the following code:
def dot[T](l: List[List[T]])(implicit num: Numeric[T]) =
{
for (row <- data)
yield for(col <- l)
yield row zip col map {a => num.times(a._1 , a._2)} reduceLeft (_+_)
and get the error: type mismatch; found : a._1.type (with underlying type T) required: T
Is there any way to get around that?
For division:
def foo[T](l: List[T])(implicit num: Numeric[T]) = num match{
case i: Integral[_] => l reduceLeft (i.quot(_, _))
case fr: Fractional[_] => l reduceLeft (fr.div(_, _))}
For +, - and * it's easier (plus, minus, times respectively):
def foo[T](l: List[T])(implicit num: Numeric[T]) = l reduceLeft (num.plus(_, _))