Given the following types:
sealed trait Pet {
val name: String
}
case class Dog(override val name: String) extends Pet
case class Cat(override val name: String) extends Pet
sealed trait Error
case object DBConnection extends Error
case object NoResults extends Error
We write a function that searches for a pet by its name.
def foo(petName: String): Either[Error, Pet] = {
val results: Either[Error, List[Pet]] = ??? // does not matter
val foundPet: Option[Pet] = results match {
case left # Left(_) => None
case Right(ps) => ps.find(_.name == petName)
}
foundPet match {
case None => Left(NoResults)
case Some(p) => Right(p)
}
}
Please ignore any improvements to the above code with respect to the database call.
Ideally, I'd prefer to write the above code as a simple for comprehension, taking advantage of the Either monad. The pattern matching is easy to read, I believe, but the for alternative would be more concise, I suspect.
How would I re-write the above code with a for-comprehension? I suppose that I could just make methods that match the return type of Either[Error, Pet], but was not sure.
Problem is Scala Either isn't a monad and it's not biased hence you can't use it in a for-comprehension: you have to get a LeftProject or RightProjection first as other poster mentioned.
If you're open for little scalaz. scalaz disjunction (\/) is right biased and follows all monad laws. when you map over it it gives you right value.
so your type will become
val results : \/[Error,List[Pet]]
and results.map will give you List[Pet] because scalaz disjunction is right biased.
this may be helpful as well
You can put the find into the for-comprehension and use toRight to convert it to Either. You also must convert these to RightProjections in order for it to work in the for-comprehension (Either does not have flatMap and map on its own).
def foo(petName: String): Either[Error, Pet] = {
val results: Either[Error, List[Pet]] = ???
for {
pets <- results.right
pet <- pets.find(_.name == petName).toRight(NoResults).right
} yield pet
}
The problem with Scala's Either[+A, +B] type is that you have to do right or left projections to get a monad (respectively right or left biased). On the other hand, scalaz's \/[+A, +B] is monadic by default. To get something really concise, with \/[+A, +B] the solution would look like this:
def foo(petName: String): \/[Error, Pet] = {
val results: \/[Error, List[Pet]] = ???
for {
pets <- results
results <- pets.find(_ == petName) \/> NoResults
} yield results
}
But then again, it's an example where using for {} yield ... isn't necessarily the shortest solution, this flatMap gives the same result:
results.flatMap(
_.find(_.name == petName) \/> NoResults
)
Either.fold is a nice and readable way. And you don't need scalaz to do that. Here is the code snippet:
results.fold(
err => Left(err),
lst => lst.find(_.name == petName).map(Right(_)).getOrElse(Left(NoResults))
)
Related
I wrote my own Either-like monad class called Maybe with either a value or an error object inside it. I want objects of this class to combine with Future, so that I can turn a Maybe[Future[T], E]] into a Future[Maybe[T, E]]. Therefore I implemented two flatMap methods:
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
sealed abstract class Maybe[+E, +V] {
def map[W](f: V ⇒ W ): Maybe[E, W] = this match {
case Value(v) ⇒ Value(f(v))
case Error(_) ⇒ this.asInstanceOf[Error[E, W]]
}
def flatMap[F >: E, W](f: V ⇒ Maybe[F, W]): Maybe[F, W] = this match {
case Value(v) ⇒ f(v)
case Error(_) ⇒ this.asInstanceOf[Error[F, W]]
}
def flatMap[W](f: V ⇒ Future[W]): Future[Maybe[E, W]] = this match {
case Value(v) ⇒ f(v).map(Value(_))
case Error(_) ⇒ Future.successful(this.asInstanceOf[Error[E, W]])
}
}
final case class Value[+E, +V](value: V) extends Maybe[E, V]
final case class Error[+E, +V](error: E) extends Maybe[E, V]
However, when I use the for comprehension to combine a Maybe and a Future which holds another Maybe the Scala compiler gives me the error message missing parameter type at the line of the outer generator:
def retrieveStreet(id: String): Future[Maybe[String, String]] = ...
val outerMaybe: Maybe[String, String] = ...
val result = for {
id ← outerMaybe // error message "missing parameter type" here!
street ← retrieveStreet(id)
} yield street
But when instead of using for I call the flatMapand mapmethods explicitly, it works:
val result2 =
outerMaybe.flatMap( id => retrieveStreet(id) )
.map( street => street )
(I also get this error message when I try to combine a Maybe with another Maybe in a for comprehension.)
So the questions are:
Shouldn't these two alternatives behave exactly the same? Why does the compiler figure out the correct flatMap method to call, when calling flatMap explicitly?
Since apparently the compiler is confused by the two flatMap implementations, is there a way to tell it (by a type specification anywhere) which one should be called in the for comprehension?
I am using Scala 2.11.8 in Eclipse.
I can't give you a comprehensive answer, but running it through scalac -Xprint:parser, I can tell you that the 2 alternatives actually desugar slightly differently, there's a good chance this is the source of your issue.
val result1 = outerMaybe
.flatMap(((id) => retrieveStreet(id)
.map(((street) => street))));
val result2 = outerMaybe
.flatMap(((id) => retrieveStreet(id)))
.map(((street) => street))
I'm not sure the title is describing my question the best but let's give it a shot.
I have a background job execution application that resembles a simple pipeline processing. There are Command objects that do some calculation and return an OUTPUT, and Worker that receive OUTPUT as input and can return Result
The object model looks something like this:
type OUTPUT <: AnyRef
trait Command[OUTPUT] {
def doSomething(): OUTPUT
}
sealed trait Worker[IN <: AnyRef, OUT <: Result] {
def work(input: IN): OUT
}
case class WorkA() extends Worker[String, LongResult] {
override def work(input: String): LongResult = LongResult(Long.MaxValue)
}
case class WorkB() extends Worker[Long, StringResult] {
override def work(input: Long): StringResult = StringResult(input.toString)
}
There are few problems with this approach:
When mapping on a collection of Worker I can't make sure the worker accepts the same OUTPUT as input.
Unless I'm mapping a List of Command, the code does not compile because of type erasure - it expects a _$1 but receives a Long or a String (everything that was previously accepted as OUTPUT)
val workers = List(
new WorkA(),
new WorkB()
)
val aSimpleCommand = new Command[Long] {
override def doSomething() = 123123123L
}
// Obviously this doesn't compile.
workers.map(worker => worker.work(aSimpleCommand.doSomething()))
I'm looking for the right Scala mechanism to disallow this at compile time. How can I map ONLY on the Worker that DO actually support OUTPUT - and in this case, only WorkB
If you want to do this at compile time you can use shapeless HLists, preserving the type of your list all the way through, and then using a Poly to handle the cases:
val myWorkers: WorkA :: WorkB :: WorkB :: HNil =
WorkA() :: WorkB() :: WorkB() :: HNil
object doWork extends Poly1 {
implicit def caseLong[A] = at[Worker[Long, A]] {
w => w.work(aSimpleCommand.doSomething())}
implicit def caseString = //whatever you want to do with a String worker
}
myWorkers map doWork
For a less safe example that doesn't need shapeless, you can match cases as long as you have concrete types:
val myWorkers: List[Worker[_, _]] = ...
myWorkers collect {
case wa: WorkA => //works
case lw: Worker[Long, _] => //doesn't work
}
If it is feasible to explicitly state all classes that extend Worker[Long, _], then you could map the workers over a partial function like so:
val res = workers map {
case b: WorkB => Some(b.work(aSimpleCommand.doSomething()))
case _ => None
}
In your example, this will return List(None, Some(StringResult(123123123)). You can also collect only the existing values:
res collect {case Some(r) => r} // List(StringResult(123123123))
Now, this isn't a very practical solution. Maybe the following thoughts help you come up with something better:
As you have already stated, because of type erasure, we cannot create our partial function to accept values of type Worker[Long, _] at runtime. ClassTag (and TypeTag) provide a solution to this problem by making the compiler create evidence accessible at runtime for the erased types. For example, the following function extracts the runtime class of a worker's input:
import scala.reflect.ClassTag
def getRuntimeClassOfInput[T: ClassTag](worker: Worker[T, _]) = implicitly[ClassTag[T]].runtimeClass
Example usage:
println(getRuntimeClassOfInput(new WorkB)) // long
The problem is that this doesn't seem to work once the workers are inside a list. I suppose that it's because once you have multiple different workers in the list, the list becomes a List[Worker[Any, Result] and you lose all type information. What might solve this problem are Heterogenous Lists because unlike the standard lists they keep the static type information of all elements.
Suppose I have the following class hierarchy:
trait A; class A1 extends A; class A2 extends A
Now I need to filter A1 instances in List[A]. I use either pattern matching or isInstanceOf.
as.filter(cond(_){case _: A1 => true}) // use pattern matching
as.filter(_.isInstanceOf[A1]) // use isInstanceOf
Does it work the same ? What would you prefer ?
Why don't you use collect? That has the added benefit that the returned list will be of the right type (List[A1] instead of List[A])
val a1s = as.collect { case x:A1 => x }
While the accepted answer gives you a good advice, please note that typecase in scala is not different than using isInstanceOf combined with asInstanceOf. This two examples are roughly equivalent:
def foo(x: Any) = x match {
case s: String = println(s"$s is a String)
case _ => println("something else")
}
def foo(x: Any) = x match {
case _ if x.isInstanceOf[String] => println(s${x.asInstanceOf[String]} is a String)
case _ => println("something else")
}
So in your specific example it doesn't really matter which of the two you use: you'll always end up doing some kind of downcasting, which is something to generally avoid.
See how the second version is considerably uglier, hence more appropriate, since you're doing a "ugly" thing in a functional language.
So, I'd go with
val a1s = as.collect{case x if x.isInstanceOf[A1] => x.asInstanceOf[A1]}
Ugly things should look ugly.
Does it work the same?
The same answer will be generated, but different code will be emitted in each case, as you might expect.
You can examine the IL which is generated in each case, as follows. Create a "test.scala" file with the following contents:
import PartialFunction.cond
trait A; class A1 extends A; class A2 extends A
class Filterer {
def filter1(as: List[A]) =
as.filter(cond(_){case _: A1 => true}) // use pattern matching
def filter2(as: List[A]) =
as.filter(_.isInstanceOf[A1]) // use isInstanceOf
}
Then run:
scalac test.scala
To examine the IL for the as.filter(cond(_){case _: A1 => true}) version, do
javap -c 'Filterer$$anonfun$filter1$1'
javap -c 'Filterer$$anonfun$filter1$1$$anonfun$apply$1'
Then to examine the IL for the as.filter(_.isInstanceOf[A1]) version, you can do
javap -c 'Filterer$$anonfun$filter2$1'
The "cond" version uses more intermediate values and instantiates more objects representing the extra anonymous functions involved.
In Scala, I am thinking of a simple monad Result that contains either a Good value, or alternatively an Error message. Here is my implementation.
I'd like to ask: Did I do something in an excessively complicated manner? Or mistakes even?
Could this be simplified (but maintaining readability, so no Perl golf)? For example, do I need to use the abstract class and the companion object, or could it be simpler to put everything in a normal class?
abstract class Result[+T] {
def flatMap[U](f: T => Result[U]): Result[U] = this match {
case Good(x) => f(x)
case e: Error => e
}
def map[U](f: T => U): Result[U] = flatMap { (x: T) => Result(f(x)) }
}
case class Good[T](x: T) extends Result[T]
case class Error(e: String) extends Result[Nothing]
object Result { def apply[T](x: T): Result[T] = Good(x) }
Now if I, for example
val x = Good(5)
def f1(v: Int): Result[Int] = Good(v + 1)
def fE(v: Int): Result[Int] = Error("foo")
then I can chain in the usual manner:
x flatMap f1 flatMap f1 // => Good(7)
x flatMap fE flatMap f1 // => Error(foo)
And the for-comprehension:
for (
a <- x;
b <- f1(a);
c <- f1(b)
) yield c // => Good(7)
P.S: I am aware of the \/ monad in Scalaz, but this is for simple cases when installing and importing Scalaz feels a bit heavy.
Looks good to me. I would change the abstract class into a sealed trait. And I think you could leave off the return types for flatMap and map without losing any readability.
I like the companion object because it calls out your unit function for what it is.
sealed class A
class B1 extends A
class B2 extends A
Assuming we have a List of objects of class A :
val l: List[A] = List(new B1, new B2, new B1, new B1)
And we want to filter out the elements of the type B1.
Then we need a predicate and could use the following two alternatives:
l.filter(_.isInstanceOf[B1])
Or
l.filter(_ match {case b: B1 => true; case _ => false})
Personally, I like the first approach more, but I often read, one should use the match-case statement more often (for reasons I do not know).
Therefore, the question is: Are there drawbacks of using isInstanceOf instead of the match-case statement ? When should one use which approach (and which approach should be used here and why) ?
You can filter like that:
l.collect{ case x: B1 => x }
That is much more readable, IMO.
There's no problem using isInstanceOf, as long as you don't use asInstanceOf.
Code that uses both is brittle, because checking and casting are separate actions, whereas using matching you have a single action doing both.
There are no difference
cat t.scala:
class A {
def x(o: AnyRef) = o.isInstanceOf[A]
def y(o: AnyRef) = o match {
case s: A => true
case _ => false
}
}
$ scalac -print t.scala
[[syntax trees at end of cleanup]]// Scala source: t.scala
package <empty> {
class A extends java.lang.Object with ScalaObject {
def x(o: java.lang.Object): Boolean = o.$isInstanceOf[A]();
def y(o: java.lang.Object): Boolean = {
<synthetic> val temp1: java.lang.Object = o;
temp1.$isInstanceOf[A]()
};
def this(): A = {
A.super.this();
()
}
}
}
The advantage of match-case is that you don't have to cast the object in case you want to perform operations on it that depend on its narrower type.
In the following snippet, using isInstanceOf seems to be fine since you don't perform such an operation:
if (obj.isInstanceOf[A]) println(obj)
However, if you do the following:
if (obj.isInstanceOf[A]) {
val a = obj.asInstanceOf[A]
println(a.someField) // someField is declared by A
}
then I'd be in favour of using match-case:
obj match {
case a: A => println(a.someField)
case _ =>
}
It is slightly annoying that you have to include the "otherwise"-case, but using collect (as hinted at by om-nom-nom) could help, at least if you work with collections inherit from Seq:
collectionOfObj.collect{ case a: A => a}.foreach(println(_.someField))