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
}
}
Related
I'm trying to perform a Natural Transformation between kinds of * -> * -> *
so I want to take F[A, B] => G[A, B]
Specifically I'm trying to define a DSL that I can then convert into actual function definitions, so MyDSL[A, B] => Function[A, B]
Here is the Natural Transformation definition:
trait ~~>[F[_, _], G[_, _]] {
def apply[A, B](fab: F[A, B]): G[A, B]
}
object ~~> {
def apply[F[_, _], G[_, _]](implicit f2g: F ~~> G): F ~~> G = f2g
}
The DSL looks like so:
sealed trait MyDSL[A, B]
object MyDSL {
case object Add1 extends MyDSL[Int, Int]
case object Show extends MyDSL[Int, String]
implicit def dsltoF: MyDSL ~~> Function = new ~~>[MyDSL, Function] {
override def apply[A, B](fab: MyDSL[A, B]): Function[A, B] = fab match {
case Add1 => i => i + 1
case Show => i => i.toString
}
}
}
Using the Natural Transformation directly works fine:
dsltoF(Add1)
output: res0: Function[Int,Int] = MyDSL$$anon$2$$Lambda$1816/700824958#6f3aa425
It even works in the case where the function returned is a method taking 2 type parameters.
When I try to define a DSL object that converts using a generic method of one type parameter it has issues.
case class Id[A]() extends MyDSL[A, A]
implicit def dsltoF: MyDSL ~~> Function = new ~~>[MyDSL, Function] {
override def apply[A, B](fab: MyDSL[A, B]): Function[A, B] = fab match {
case Id() => identity[A] _
case Add1 => i => i + 1
case Show => i => i.toString
}
}
I get a found A required B compilation error.
Scala doesn't recognize that B is A in this case.
I get why, as the type parameters A & B aren't necessarily correlated properly to the definition of the function I am returning, therefore even writing:
case Add1 => i => i + 1
there is red lines in IntelliJ as it doesn't realize that even though Add "is a" MyDSL[Int, Int]. Though Scala is ok with this.
The type parameters are open to all possibilities on the method signature of apply on the Natural Transformation, but in this case it needs some sort of restriction. My guess is since there is no value within the DSL case class to restrict the type parameter, it comes down to the pattern match, which is already past where Scala interprets the signature of the method, and therefore it expects a different type B and it barks.
I can of course get around this via .asInstanceOf nastiness, but I mean come on.
Any thoughts of a different strategy to get this to work would be appreciated.
That's a known restriction in the type inference system in the current versions of the language, which should be lifted in future versions.
In this case, you can use type variables in the pattern match to work around this restriction:
import scala.language.higherKinds
trait ~~>[F[_, _], G[_, _]] {
def apply[A, B](fab: F[A, B]): G[A, B]
}
object ~~> {
def apply[F[_, _], G[_, _]](implicit f2g: F ~~> G): F ~~> G = f2g
}
sealed trait MyDSL[A, B]
object MyDSL {
case class Id[A]() extends MyDSL[A, A]
case class Const[A, B](constantResult: B) extends MyDSL[A, B]
case object Add1 extends MyDSL[Int, Int]
case object Show extends MyDSL[Int, String]
implicit def dsltoF: MyDSL ~~> Function = new (MyDSL ~~> Function) {
override def apply[A, B](fab: MyDSL[A, B]): Function[A, B] = fab match {
case _: Id[x] => identity[x] _
case c: Const[a, b] => (_ => c.constantResult)
case Add1 => i => i + 1
case Show => i => i.toString
}
}
}
Essentially: if there is no "place" where the compiler could deposit more specific type information, just give it a type-variable in the pattern so it can attach the inferred type information to it.
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.
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.
How it's done in Scala:
sealed trait Option[+A] {
def get: A
def isEmpty: Boolean
def map[B](f: A => B): Option[B] =
if (isEmpty) None else Some(f(this.get))
}
object None extends Option[Nothing] {
def isEmpty = true
def get = throw new NoSuchElementException("None.get")
}
case class Some[+A](x: A) extends Option[A] {
def isEmpty = false
def get = x
}
How I would assume it in OOP world:
sealed trait Option[+A] {
def map[B](f: A => B): Option[B]
}
object None extends Option[Nothing] {
def map[B](f: Nothing => B): Option[B] = this
}
case class Some[+A](get: A) extends Option[A] {
def map[B](f: A => B): Option[B] = Some(f(get))
}
What's wrong with the latter?
Functional programming in Scala is using match in Option[A] trait, which is the third way (looks like Haskell, but why?) Why not utilize subtype polymorphism?
UPDATE: Third way I mentioned:
sealed trait Option[+A] {
def map[B](f: A => B): Option[B] = this match {
case None => None
case Some(a) => Some(f(a))
}
}
object None extends Option[Nothing] {
}
case class Some[+A](get: A) extends Option[A] {
}
I'm not sure whether you intended to, but you left out the declarations of isEmpty and get, which are needed by anyone that wants to check the contents of an arbitrary Option without needing to downcast to Some. Since both of these methods need to be defined by both subclasses, and since map can be defined in terms of them, I think the reasoning was that it would be better to define map in one place leveraging the subclass implementations of the other methods, rather than defining map in three places.
I guess that since scala support both functional and imperative and it aiming java programs, this is one of the stuff that make them fill more comfortable.
From java programmer
val opt: Option[String] = ???
if (!opt.isEmpty) {
//do something with opt.get
} else {
//do some default...
}
may be more understandable than functional way (even with getOrElse).
#Victor Moroz wrote in one of the comments about using pattern matching instead of the this match { None => default_val; Some(v) => v }
This in addition to be harder to read by programmer new to the functional world, will cost much more, since Option is intended to be use a lot, and instanceOf cost more than a simple if.
I know there are already some ways of making traversal generic in scala, but I'm trying to define a simple trait that encapsulates a traversable type. However, I'm having trouble getting the type signatures to work out. A first attempt would be something like the following:
trait Traversable1[B] {
def head: Option[B]
def next: Traversable1[B]
}
This works well, except I want next to return an object that has the same type as the original traversable, not the more generic traversable type. For example, if List has the trait Traversable1, it's next method should return something of type List, not Traversable1. Thus, my second attempt was the following:
trait Traversable2[A[B] <: Traversable2[A[B]] {
def head: Option[B]
def next: A[B]
}
Here, A could equal List, so next would return a List[B]. Unfortunately, this code does not compile: A[B] takes no type parameters, expected: one
How can I achieve what I'm trying to do?
You could create a trait like:
trait Traversable[T[_]] {
def head[A](t: T[A]): Option[A]
def next[A](t: T[A]): T[A]
}
then implement it for lists like:
implicit val listTraversable = new Traversable[List] {
def head[A](l: List[A]) = l match {
case Nil => None
case x::_ => Some(x)
}
def next[A](l: List[A]) = l.tail
}
You can then make use of it using the 'type class' pattern by taking an implicit implementation of the trait to do the work e.g.
def foreach[T[_], A](t: T[A], f: A => Unit)(implicit trav: Traversable[T]): Unit = {
trav.head(t) match {
case Some(v) =>
f(v)
foreach(trav.next(t), f)
case None => ()
}
}
and call it with
foreach(List(1,2,3), println)