Choosing which pattern to use - scala

I have following trait:
sealed trait Sum[+A, +B] {
def fold[C](error: A => C, success: B => C): C =
this match {
case Failure(v) => error(v)
case Success(v) => success(v)
}
}
final case class Failure[A](value: A) extends Sum[A, Nothing]
final case class Success[B](value: B) extends Sum[Nothing, B]
As you can see, there is a fold method implementation.
I could move the fold method into a companion object as follow:
sealed trait Sum[+A, +B]
final case class Failure[A](value: A) extends Sum[A, Nothing]
final case class Success[B](value: B) extends Sum[Nothing, B]
object Sum{
def fold[A, B, C](s: Sum[A,B], error: A => C, success: B => C): C =
s match {
case Failure(v) => error(v)
case Success(v) => success(v)
}
}
What is more convenient pattern, the first or second example and in which situation?

The latter will probably not work as you intend, since this in that case is the object Sum not the instance of either Failure or Success.
Anyway, I'd move the implementations to case classes:
case class Failure[A](value: A) extends Sum[A, Nothing] {
def fold[C](error: A => C, success: B => C): C = error(value)
}
case class Success[A](value: B) extends Sum[A, Nothing] {
def fold[C](error: A => C, success: B => C): C = success(value)
}

The second one doesn't work, since this is pointing to the Sum companion object, and the type variables A and B aren't defined.
Therefore use the first pattern!

I'd prefer the first (or the modification in Tomasz Perek's answer). The second should be changed to
def fold[A, B, C](s: Sum[A,B])(error: A => C, success: B => C): C =
s match {
case Failure(v) => error(v)
case Success(v) => success(v)
}
so that the compiler already knows A and B by the time it gets to type-checking the error and success parameters.

Related

how to define upper bounds for scala method

how do you define a Scala method such that it would take in the subclass of any type A without throwing a compilation error?
trait A
case class B extends A
case class C extends A
case class W[T](abc: Option[T]= None)
def methodOne(a: A): W[A] = {
a match {
case b:B => methodTwo() // throws compilation error
case c:C => methodThree() // throws compilation error
}
}
def methodTwo(): W[B] = y
def methodThree(): W[C] = z
Have tried something like
def methodOne[T <: A](a: A): W[T]
but it doesn't allow to compile still
If you want forall T <: A to imply W[T] <: W[A], you need to make W covariant:
case class W[+T](abc: Option[T] = None)
object X {
def methodOne(a: A): W[A] = {
a match {
case b: B => methodTwo()
case c: C => methodThree()
}
}
def methodTwo(): W[B] = ???
def methodThree(): W[C] = ???
}
For basic coverage of variance, see this post.
You need to make W covariant. You can do this easily by defining it as W[+T]:
case class W[+T](abc: Option[T] = None)
This way if B is a subtype of A, W[B] is also a subtype of W[A].
Option for example is defined as Option[+T], therefore Option[B] is a subtype of Option[A].
You can checkout the official scala docs for more details

Cannot resolve symbol A

I have following trait:
sealed trait Sum[+A, +B]
final case class Failure[A](value: A) extends Sum[A, Nothing]
final case class Success[B](value: B) extends Sum[Nothing, B]
object Sum {
def flatMap[AA >: A, B, C](s: Sum[AA, B], f: B => Sum[AA, C]): Sum[AA, C] =
s match {
case Failure(v) => Failure(v)
case Success(v) => f(v)
}
def fold[A, B, C](s: Sum[A, B], success: A => C, failure: B => C): C =
s match {
case Failure(v) => failure(v)
case Success(v) => success(v)
}
def map[A, B, C](s: Sum[A, B], success: A => C): Sum[A,C] =
fold(s, succ => Success(success(succ)), fail => Failure(fail))
}
and the compiler complain:
Cannot resolve symbol A
by:
flatMap[AA >: A, B, C]
What am I doing wrong?
What am I doing wrong?
You're defining a lower bound for a type parameter that doesn't exist. What is A in this context? You're telling the compiler "I want AA to have a lower bound of type A", but the compiler doesn't know a generic type parameter A because it wasn't declared.
If you want to have two type parameter, where one is a lower bound on another (or more generally any bound), it needs to be declared first:
def flatMap[A, AA >: A, B, C]

Why it is possible to pass an other type

I have following code snippet:
sealed trait Option[+A] {
def map[B](f: A => B): Option[B] = this match {
case None => None
case Some(a) => Some(f(a))
}
def getOrElse[B>:A](default: => B): B = this match {
case None => default
case Some(a) => a
}
def orElse[B>:A](ob: => Option[B]): Option[B] =
this.map(Some(_)).getOrElse(ob)
}
case class Some[+A](get: A) extends Option[A]
case object None extends Option[Nothing]
The function orElse has a argument ob of type Option[B]. In the function body, I pass ob to the function getOrElse but it expects a type of B, how it is possible?
Because B can be any type?
Type A is identified once at the top. Type B, on the other hand, is being identified/defined separately at each method.
So if orElse receives an Option[B] for some unknown type B and passes it to getOrElse then, as far as getOrElse is concerned, that becomes the new B.
This might make a little more sense if you had used C instead of B for the getOrElse method, and used D instead of B for the orElse method. Everything would work the same but it'd be easier to see the non-relationships.
It's analogous to value parameters. If we have a method f(x:Int) = g(x-1) the received parameter is called x. The method g(x: Int)=... also calls its parameter x but that doesn't mean the values are the same.

Scala: Cannot resolve symbol in function

I want to reimplement again scala left/right/either. Here is my code:
case class Left[+E](get: E) extends Either[E, Nothing]
case class Right[+A](get: A) extends Either[Nothing, A]
sealed trait Either[+E, +A] {
def orElse[EE >: E, B](b: => Either[EE, B]): Either[EE, B]
this match {
case Left(_) => b // error here
case Right(a) => Right(a)
}
}
I don't know what I meet error at case Left(_) => b:
Cannot resolve symbol b
But this method will not throw error:
def orElse[EE >: E, AA >: A](b: => Either[EE, AA]): Either[EE, AA] =
this match {
case Left(_) => b
case Right(a) => Right(a)
}
Please tell me this.
As #jwvh stated in the comment, the you are missing an = in your definition:
def orElse[EE >: E, B](b: => Either[EE, B]): Either[EE, B] = ...
Without the =, the compiler sees an abstract orElse method and some random initialisation code, rather than an implemented method. Sometimes using braces helps get around cases like this
However after adding the = you get type errors because B must be related to A in Either, otherwise this won't match the passed value (similarly to how you got AA), leaving you with:
def orElse[EE >: E, B >: A](b: => Either[EE, B]): Either[EE, B] = ...
Replace the B with AA and you have your original working example

Pattern Matching on Either

From Functional Programming in Scala, I'm trying to implement Either.map.
trait Either[+E, +A] {
def map[B](f: A => B): Either[E, B] = this match {
case Either(x: E, y: A) => Right(f(y))
case _ => Left()
}
}
One error shows up on compilation, among others. I'm not showing them since I appear to be missing the concept of implementing Either.
Either.scala:3: error: value Either is not a case class constructor,
nor does it have an unapply/unapplySeq method
case Either(x: E, y: A) => Right(f(y))
Please advise me on implementing it.
The error message says that you cannot use Either as a case class constructor. IOW, Either is equivalent to an abstract class since you have encoded it as a trait with its own implementable methods. Let's assume you have the following encoded representation of Either, Left and Right:
sealed trait Either[+E, +A] {
def map[B](f: A => B): Either[E, B] = ???
}
// Left signifies error condition
// Right is something Right, along with its message.
case class Left[+E](err: E) extends Either[E,Nothing]
case class Right[+E](msg: E) extends Either[Nothing,E]
You can write the map function as:
def map[B](f: A => B): Either[E, B] = this match {
case Right(v) => Right(f(v))
case Left(e) => Left(e)
}
Here I'm simply saying that if you encounter something that's supposed to be a right value, perform some function computation on it and return it exactly as it should be - a Right. Since Either is a sealed trait(mainly for convenience), the only other type could be a Left which I return as is. Read more about Either
try this one
trait Either[+E, +A] {
def map[B](f: A => B): Either[E, B] = this match {
case Right(y) => Right(f(y))
case left: Left[E] => left
}
}