I'm working on a small program using Scala Cats. I'm encountering lots of type errors when trying to use EitherT with State and for comprehensions. For instance:
import cats.data.{EitherT, State}
import cats.data.State.get
object Test {
type IntState[T] = State[Int, T]
type IntStateEither[T] = EitherT[IntState, String, T]
val test: IntStateEither[Unit] = for {
isValid <- EitherT.right(get.map((it: Int) => it % 2 == 0))
_ <- if (!isValid) EitherT.leftT("invalid number") else EitherT.rightT(()) // *
} yield ()
}
Which gives me:
(...) Test.scala:12: type mismatch;
found : cats.data.EitherT[[A(in value <local Id>)]A(in value <local Id>),_1,Unit] where type _1 <: String
required: cats.data.EitherT[[A(in class IndexedStateT)]cats.data.IndexedStateT[cats.Eval,Int,Int,A(in class IndexedStateT)],String,Unit]
one error found
If I comment out the line marked (*) above, this code compiles. I think I'm following the instructions on the Cats website under "From A or B to EitherT[F, A, B]" correctly, but do I need to give more type hints? If yes, I'm not sure where I can add them.
Any pointers are greatly appreciated!
I'm using Cats 2.0.0 and Scala 2.13.2.
It seems that the problem is that the compiler is not able to infer the correct types for EitherT.leftT and EitherT.rightT.
You can fix those errors using explicit types like: EitherT.rightT[IntState, String], or if you only need one flatMap call, it seems doing it explicitly does work:
val test: IntStateEither[Unit] =
EitherT
.right[String](State.get[Int].map(it => it % 2 == 0))
.flatMap { isValid =>
if (isValid) EitherT.rightT(())
else EitherT.leftT("invalid number")
}
PS: It may be worth checking if bm4 helps.
Related
I am trying to understand the type parameters when applied to a function.
I would like to use Generic Types in the below method but using String and Int for my understanding.
When I define a function as below
def myfunc[Int](f:String => Int):Int = {
Integer.min(1,2)
}
it complains
found : scala.this.Int
required: Int&0
Integer.min(1,2)
However if I remove the return type of the function ( which I understand is not required), it compiles fine.
I am not able to infer why removing the return type makes the compilation successful.
Appreciate your help.
-Amit
Try
def myfunc(f:String => Int):Int = {
Integer.min(1,2)
}
When you write def myfunc[Int](f:String => Int):Int you declare type parameter Int, which hides standard type scala.Int. This is the same as if you declared def myfunc[A](f:String => A):A. When you remove return type it's inferred to be scala.Int, i.e. def myfunc[A](f:String => A) is def myfunc[A](f:String => A):Int
If you want to use generics, first you have to understand that the name of the variable types starts capitalized and they are names, just that so [Int] in your function is the name of the type variable, an example:
object Main extends App{
val f: String => Int = s => 4
println(myfunc(f, "nothing useful"))
def myfunc[A,B](f:A => B, x: A):B = {
f(x)
}
}
here the names are A and B and the return type is of type B
Question: What's the difference between these 3 methods?
def myfunc1[X](f:String => X):X =
Integer.min(1,2)
def myfunc2[Int](f:String => Int):Int =
Integer.min(1,2)
def myfunc3[IDontGetTypeParameters](f:String => IDontGetTypeParameters):IDontGetTypeParameters =
Integer.min(1,2)
Answer: Nothing. From the compiler's point of view they are the same, and they fail to compile for the same reason: each is defined to return the type of the type parameter but tries to return an integer (Scala.Int) instead.
A quick one liner:
def myfunc(f:String => Int):Int = Integer.min(1,2)
It's good trying to make your own examples, but have you tried any examples from books, articles or tutorials? There's probably a good one in Scala for the Impatient by Cay Horstmann.
Here's a decent example from the Tour de Scala:
def listOfDuplicates[A](x: A, length: Int): List[A] = {
if (length < 1)
Nil
else
x :: listOfDuplicates(x, length - 1)
}
Sometimes you can omit the type parameter, but let's ignore that for now and declare the types explicitly:
listOfDuplicates[Int](43, 5) // Should give a list with 43 five times
listOfDuplicates[String]("Hello, world! ", 3) // "Hello, world!" thrice
listOfDuplicates[(Int, Int)]((0, 1), 8) // The pair (0, 1) eight times
This shows that A can be Int, String, (Int, Int) or just about anything else we can think of. Not sure you'd ever have a practical need for this, but you can even do something like this:
def wrapLength(str: String): Int = str.length
listOfDuplicates[String => Int](wrapLength(_), 2)
Here's a Scastie snippet in which you can play around with this.
Your generic type name shouldn't be one of the reserved words in Scala. Int itself is a reserved word for a type.
In this cases, for simplicity and understanding, we use some basic characters like T or R as the generic type if you really keen to use generics for other functions.
I have a unit test, which test some solution. But this test code can also be applied for testing the other, very similar solution. What I want to make is code of test be generic to be applied to both solutions, like this:
describe("when table contains all correct rows") {
it("should be empty") {
def check[T](func: T => List[Row]) = {
val tableGen = new TableGenerator()
val table: Vector[Row] = tableGen.randomTable(100)
.sortWith(_.time isBefore _.time).distinct
val result: List[Row] = func(table)
assert(result.isEmpty)
}
check(Solution.solution1)
check(Solution.solution2)
}
}
where solutions have types:
solution1: IndexedSeq[Row] => List[Row]
solution2: Seq[Row] => List[Row]
how check() function has to be written to be able to do that?
And what's the best approaches to write this (might be in other way) with eliminated code duplication?
Update:
When I try to compile this code I get type mismatch error in func(table):
Error:(36, 29) type mismatch;
found : table.type (with underlying type scala.collection.immutable.Vector[com.vmalov.tinkoff.Row])
required: T
val result = func(table)
For this to work, you need to be able to pass a Vector[Row] to func, so any Vector[Row] has to be a T; that is, T is a supertype of Vector[Row]. You can tell this to the compiler by using a type parameter bound:
def check[T >: Vector[Row]](func: T => List[Row])
Alternately, by the above reasoning, a function T => List[Row] will also be a function Vector[Row] => List[Row] precisely when T is a supertype of Vector[Row], and the Scala compiler knows about this (functions are contravariant in their argument type(s)). So this signature is equivalent to simpler
def check(func: Vector[Row] => List[Row])
Of course, you can generalize this, but how much depends on your specific desires. E.g. you can replace List[Row] with Seq[Row] (everywhere), or with a type parameter and pass an extra function to check:
def check[A](func: Vector[Row] => A)(test: A => Boolean) = {
val table = ...
val result = func(table)
assert(test(result))
}
check(Solution.solution1)(_.isEmpty) // the compiler infers A is List[Row]
Your case, maybe is enough to abstract the type on a more specific way, like defining that you are expecting a Travesable.
def check[S[_] : Traversable](func: S[Row] => List[Row])
That would accept either Seq or IndexedSeq as valid parameter, while it also be limiting it.
I hope it helps
EDITED: Check Alexey Romanov Answer, as with this you will not be able to call func the way you do it. Sorry about that
def check(func: Vector[Row] => List[Row])
Is there the concept of a Future that cannot fail in Scala?
I'm transforming a Future[Result], which may fail—therefore I handle both a Failure and a Success—into a Future[Option[String]], carrying an optional error message derived from the failure or success states. So far, so good.
Thing is now, I would like to formally (i.e., with the help of the type system) remember that this future will always hold a Success and that I won't need to handle the failure case in the future.
Is there a smart way to do this?
You cannot do that "with the help of type system" because there is no way for the type system to guarantee a Future will not fail, even if you promise that it won't.
Consider this:
Future { doStuff(); }
.recover { case _ => "Failed!" } // Now it always succeeds
.map { _ => Seq.empty[String].head } // Now it does not.
Even if you were going to make any further transformations impossible, once the Future has been declared to always succeed, that still does not help, because the exception handler (or whatever you do to convert the original future to the "always succeeding one") could throw.
Update: as pointed out in a comment below, the code snippet above is incorrect: the result of .map is not the same Future as the result of .recover. The point stands however. Here is the correct illustration:
Future { doStuff }
.recover { case _ => Seq.empty[String].head }
Isn't this what type-tagging is for?
scala> type Tagged[U] = { type Tag = U }
defined type alias Tagged
scala> type ##[T, U] = T with Tagged[U]
defined type alias $at$at
scala> trait OK ; trait Uncertain
defined trait OK
defined trait Uncertain
scala> type Sure[A] = Future[A] ## OK
defined type alias Sure
scala> type Unsure[A] = Future[A] ## Uncertain
defined type alias Unsure
scala> val f = Future.successful(42).asInstanceOf[Sure[Int]]
f: Sure[Int] = Future(Success(42))
then
scala> object X { def p(f: Sure[_]) = "sure" ; def p(f: Unsure[_])(implicit d: DummyImplicit) = "unsure" }
defined object X
scala> X.p(f)
res1: String = sure
It doesn't remain sure under map, of course.
Hi all I am fairly new to Scala coming from C#.
I am attempting to write my own version of accumulate ( fold) I am wondering why I am running into some issues with the following:
def accumulate[T](list : List[T], initial: T, f: (T, T) => T) : T = {
#tailrec def loop[T](list: List[T], accum: T) : T =
if(list.length == 0)
accum
else{
val head : T = list.head
val res : T = f(accum,head)
loop[T](list.tail, res)
}
loop(list,initial)
}
I am getting the following error:
type mismatch;
found : accum.type (with underlying type T)
required: T
val res : T = f(accum,head)
^
I cant see how I have a type mismatch considering everything is type T.
Any thoughts / help would be appreciated.
Blair
You should just remove type parameter from loop method. Replace loop[T] with loop.
With loop[T] you are creating new type parameter with name T, so T outside loop method and T in loop method are different type aliases with the same name.
It's called shadowing.
See these answers for similar problems:
Scala type parameter error, not a member of type parameter
Scala, Extend object with a generic trait
Generic type inference in Scala
The problem is that with the inner function loop you are defining a new type T that is shadowing the outer type T.
The compiler sees them as defining different types. If you simply remove the T type parameter from loop (including the recursive call loop(list.tail, res)) you should find it compiles just fine.
Scala Version 2.10.0
I create a function like this.
def rm(workingSet: List[_])(item: Any)(f:(List[_], Any) => List[_]) = f(workingSet, item)
I get the following error:
scala> val data = List(1,2,3)
scala> rm(data)(1)((list, item)=>list filter (_ != item))
<console>:10: error: missing parameter type for expanded function ((x$1) => x$1.$bang$eq(item))
rm(data)(1)((list, item)=>list filter (_ != item))
^
Can somebody explain this problem?
Thanks!
There are times when the compiler cannot infer the type and you have to help it. Try "list.filter(_ != item)" - using the "." notation often does the trick. If that doesn't do it, you can always do "list filter { li: Int => li != item }". FWIW, the scala 2.10 REPL doesn't seem to have a problem inferring the parameter type for me.
The only way I could get your example to compile was to introduce a type parameter:
def rm[A](workingSet: List[A])(item: A)(f:(List[A], A) => List[A]) = f(workingSet, item)
Any particular reason why you are using existentials and Any?