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]
Related
I'm reading some articles about ScalaZ and have a question about understanding it. In this article, we generalize the sum function, to abstract away the type to be summed.
def sum[T](xs: List[T])(implicit m: Monoid[T]) = //...
Where
trait Monoid[A] is defined as follows:
trait Monoid[A] {
def mappend(a1: A, a2: A): A
def mzero: A
}
Yes, this is pretty clear. Monoid here corresponds to the algebraic monoid structure. Now in this article it abstracts over lists. To do this we define the following trait:
trait FoldLeft[F[_]] {
def foldLeft[A, B](xs: F[A], b: B, f: (B, A) => B): B
}
object FoldLeft {
implicit val FoldLeftList: FoldLeft[List] = new FoldLeft[List] {
def foldLeft[A, B](xs: List[A], b: B, f: (B, A) => B) = xs.foldLeft(b)(f)
}
}
So now we can define the sum function as follows:
def sum[M[_]: FoldLeft, A: Monoid](xs: M[A]): A = {
val m = implicitly[Monoid[A]]
val fl = implicitly[FoldLeft[M]]
fl.foldLeft(xs, m.mzero, m.mappend)
}
I'm not a theory category expert, but it looks like Applicative functor to me. Is that correct? Can we provide such similarity to category theory.
Applicative functor is a type class with two operations: A => F[A] and F[A => B] => F[A] => F[B]. None of operations you mentioned has such signature. FoldLeft is more like Foldable. It's a different type class, a parent of Traversable (aka Traverse). And Traversable is connected with Applicative.
trait Functor[F[_]] {
def fmap[A, B](f: A => B)(fa: F[A]): F[B]
}
trait Applicative[F[_]] extends Functor[F] {
def pure[A](a: A): F[A]
def ap[A, B](ff: F[A => B])(fa: F[A]): F[B]
override def fmap[A, B](f: A => B)(fa: F[A]): F[B] = ap(pure(f))(fa)
}
trait Foldable[T[_]] {
def foldr[A, B](op: A => B => B)(seed: B)(ta: T[A]): B =
(foldMap(op)(ta) _)(seed)
def foldMap[A, M](f: A => M)(ta: T[A])(implicit monoid: Monoid[M]): M =
foldr[A, M](a => m => monoid.append(f(a), m))(monoid.empty)(ta)
}
trait Traversable[T[_]] extends Functor[T] with Foldable[T] {
def traverse[F[_]: Applicative, A, B](k: A => F[B])(ta: T[A]): F[T[B]] =
sequence[F, B](fmap[A, F[B]](k)(ta))
def sequence[F[_]: Applicative, A](tfa: T[F[A]]): F[T[A]] =
traverse[F, F[A], A](fa => fa)(tfa)
override def fmap[A, B](f: A => B)(ta: T[A]): T[B] = traverse[Id, A, B](f)(ta)
override def foldr[A, B](op: A => B => B)(seed: B)(ta: T[A]): B =
(traverse[Const[B => B]#λ, A, B](op)(ta) _)(seed)
override def foldMap[A, M: Monoid](f: A => M)(ta: T[A]): M =
traverse[Const[M]#λ, A, M](f)(ta)
}
type Id[A] = A
trait Const[C] {
type λ[A] = C
}
Type class Functor means you have a "container" F[_] and you know how to apply function f: A => B inside this container. Type class Applicative means you know how to pack a value a: A inside this container and how to apply a "function" F[A => B] to a "value" F[A]. Foldable means you know how to fold your container using binary operation A => B => B and starting value B and receiving result B. Traversable means you know how to traverse your container executing applicative effect A => F[B] in every "node".
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 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
I have two methods declared in object List:
def reduce[A, B >: A](l: List[A])(f: (B, B) => B): B =
reduceLeft(l)(f)
def reduceLeft[A, B >: A](l: List[A])(op: (B, A) => B): B = ???
I've borrowed the signatures from the scala.collection.TraversableOnce class. (I'm re-creating my own classes for pedagogical reasons).
The compiler is giving me this error:
[error] /.../List.scala:159: type mismatch;
[error] found : (B, B) => B
[error] required: (A, A) => A
[error] reduceLeft(l)(f)
[error] ^
my List class is
final case class ::[A](head: A, tail: List[A]) extends List[A] {
override def isEmpty: Boolean = false
}
sealed trait List[+A] {
def head: A
def tail: List[A]
def isEmpty: Boolean
def ::[B >: A](x: B): List[B] =
datastructures.::(x, this)
}
how can the TraversableOnce definition get away with this? Is it something to do with me not having defined the method as an infix operation?
sealed trait List[+A] {
...
def reduce(op: (B,B) => B):B = reduceLeft(op) // e.g.
... //reduceLeft...
}
Update
I've tried it in the way the TraversableOnce class declares in infix to the trait and it seems to work (see below), however I'm still curious as to why the object definition doesn't work.
sealed trait List[+A] {
...
def reduce[B >: A](f: (B, B) => B): B =
self.reduceLeft(f)
def reduceLeft[B >: A](op: (B, A) => B): B = {
if (isEmpty)
throw new UnsupportedOperationException("empty.reduceLeft")
var first = true
var acc: B = 0.asInstanceOf[B]
for (x <- self) {
if (first) {
acc = x
first = false
}
else acc = op(acc, x)
}
acc
}
#tailrec
final def foreach[U](f: A => U): Unit = { f(head); tail.foreach(f); }
...
}
Here's what's happening here: when you call reduceLeft(l)(f), you first call reduceLeft(l), with l: List[A]. Since your reduceLeft takes two type arguments, but you're not specifying them explicitly, and so far it only has A to work with. So, compiler infers the types as best as it can, using A for both types. You can see this by extracting this partial application into variable:
val partiallyApplied: ((A, A) => A) => A = reduceLeft(l)
Then, when you apply the second argument list with f: (B, B) => B, the types mismatch.
The fix is simple - explicitly state the types when calling reduceLeft:
def reduce[A, B >: A](l: List[A])(f: (B, B) => B): B = {
reduceLeft[A, B](l)(f)
}
the code in question
trait Functor[F[_]] {
def map[A, B](f: A => B): F[A] => F[B]
}
sealed abstract class Free[F[_], A]
case class Return[F[_], A](x: A) extends Free[F, A]
case class Suspend[F[_], A](x: F[Free[F, A]]) extends Free[F, A]
case class Bind[F[_], A, B](x: () => Free[F, A], f: A => Free[F, B]) extends Free[F, B]
// this is the problem child
def liftF[F[_], A](x: => F[A])(implicit F: Functor[F]) =
Suspend[F, A](F.map { Return[F, A] }(x))
Now for some reason in the eclipse scala ide I'm getting a error with liftF
this error
- type mismatch; found : F[core01.Free.Return[F,A]] required: F[core01.Free[F,A]] Note: core01.Free.Return[F,A] <: core01.Free[F,A], but type
F is invariant in type _. You may wish to define _ as +_ instead. (SLS 4.5)
Now in the scalaz source there's no variance annotation, so what's the deal here? why the need for the variance annotation? is there are really need or is there a way around it?
I think you just have the functor arguments backwards on F.map. Give this a try:
def liftF[F[_], A](x: => F[A])(implicit F: Functor[F]) =
Suspend[F, A](F.map(x) { Return[F, A] } )
println(liftF(List(1, 2)))
"Suspend(List(Return(1), Return(2)))"
Note that either way you apply the elements to functor map you'll get the same result (you're version and the scalaz version):
def mapReverse[F[_], A, B](implicit F: Functor[F]) = {
(f:A => B) => (fa:F[A]) => F.map(fa)(f)
}
val reverse = mapReverse(F)({
Return[F, A]
})(x)
val normal = F.map(x)({
Return[F, A]
})
In this case reverse and normal are both F[Return[F, A]]. The way you apply the parameters is only helpful in the context of Suspend:
Suspend[F, A](F.map(x)({ Return[F, A] })) // works great
Suspend[F, A](normal) // fails to compile
Suspend[F, A](reverse) // fails to compile
I'm sure if you dig through the scala language spec long enough you can find out why the type inference works this way. If I had to guess, when fa is applied to F.map you get a function that's of type (A => B) => F[B]. So the compiler probably looks and sees that Suspend takes a Free so it makes this (A => Free[F, A]) => F[Free[F, A]] which will gladly take Return[F, A].apply as an argument. When you apply the arguments the other way you're strongly typed to Return instead of inferring a function Free.