Can anyone tell me if something in the line with the following syntax is possible in Scala?
#annotation.tailrec
def traverse[E,A,B](es: List[A])(f: A => Either[E, B]): Either[E, List[B]] = {
def go(es: List[A], rs: Either[E, List[B]]): Either[E, List[B]] = {
es match {
case Nil => rs
case x::xs => for {
Right(b) <- f(x);
Right(ls) <- rs
} yield go(xs, Right(b::ls))
}
}
go(es, Right(List()))
}
I keep getting the following syntax exception
Error:(47, 12) constructor cannot be instantiated to expected type;
found : A$A400.this.Right[A]
required: List[?B3] where type ?B3 <: B (this is a GADT skolem)
Right(ls) <- rs
^
To be honest, I'm not entirely sure what the aim of the function is, but, guessing at what f is, here's something that may do what you want?
#annotation.tailrec
def f[A, B, E](e: A): Either[E, B] = ???
def go[A, B, E](es: List[A], rs: Either[E, List[B]]): Either[E, List[B]] = {
es match {
case Nil => rs
case x :: xs => (f(x), rs) match {
case (Right(b), Right(ls)) => go(xs, Right(b :: ls))
}
}
go(es, Right(List()))
}
Related
I'm working through the book Functional Programming in Scala, and at the end of the data structures chapter you are asked to implement the filter method in terms of flatMap. Here are the necessary functions and implementations:
sealed trait List[+A]
case object Nil extends List[Nothing]
case class Cons[+A](head: A, tail: List[A]) extends List[A]
object List {
def apply[A](as: A*): List[A] = {
if (as.isEmpty) Nil
else Cons(as.head, apply(as.tail: _*))
}
def append[A](l1: List[A], l2: List[A]): List[A] = {
foldRight(l1, l2)((elem, acc) => Cons(elem, acc))
}
def concat[A](ls: List[List[A]]): List[A] = {
foldLeft(ls, Nil: List[A])(append)
}
def map[A, B](l: List[A])(f: A => B): List[B] = {
foldRight(l, Nil: List[B])((elem, acc) => Cons(f(elem), acc))
}
def filter[A](l: List[A])(f: A => Boolean): List[A] = {
List.flatMap(l)(a => if (f(a)) List(a) else Nil)
}
def flatMap[A, B](l: List[A])(f: A => List[B]): List[B] = {
concat(map(l)(f))
}
def foldRight[A, B](l: List[A], z: B)(f: (A, B) => B): B = {
l match {
case Nil => z
case Cons(h, t) => f(h, foldRight(t, z)(f))
}
}
def foldLeft[A, B](l: List[A], z: B)(f: (B, A) => B): B = {
l match {
case Nil => z
case Cons(h, t) => foldLeft(t, f(z, h))(f)
}
}
}
The actual function call is here:
val x = List(1, 2, 3, 4, 5)
List.filter(x)(_ < 3)
As far as I can follow, after the map step you will have a List that looks like this:
Cons(Cons(1, Nil), Cons(2, Nil), Cons(Nil, Nil)...
I'm having trouble seeing where elements that are Nil are filtered out from the final result.
They are not "filtered out". They simply disappear after you apply concat on the list of lists, because concatenation with an empty list does nothing.
How do I remove explicit casting asInstanceOf[XList[B]] in Cons(f(a), b).asInstanceOf[XList[B]] inside map function? Or perhaps redesign reduce and map functions altogether? Thanks
trait XList[+A]
case object Empty extends XList[Nothing]
case class Cons[A](x: A, xs: XList[A]) extends XList[A]
object XList {
def apply[A](as: A*):XList[A] = if (as.isEmpty) Empty else Cons(as.head, apply(as.tail: _*))
def empty[A]: XList[A] = Empty
}
def reduce[A, B](f: B => A => B)(b: B)(xs: XList[A]): B = xs match {
case Empty => b
case Cons(y, ys) => reduce(f)(f(b)(y))(ys)
}
def map[A, B](f: A => B)(xs: XList[A]): XList[B] = reduce((b: XList[B]) => (a: A) => Cons(f(a), b).asInstanceOf[XList[B]])(XList.empty[B])(xs)
You can merge two argument lists into one by replacing )( by ,:
def reduce[A, B](f: B => A => B, b: B)(xs: XList[A]): B = xs match {
case Empty => b
case Cons(y, ys) => reduce(f, f(b)(y))(ys)
}
def map[A, B](f: A => B)(xs: XList[A]): XList[B] =
reduce((b: XList[B]) => (a: A) => Cons(f(a), b), XList.empty[B])(xs)
This will force the type inference algorithm to consider both first arguments of reduce before making up its mind about what B is supposed to be.
You can either widen Cons to a XList[B] at the call site by providing the type parameters explicitly:
def map[A, B](f: A => B)(xs: XList[A]): XList[B] =
reduce[A, XList[B]]((b: XList[B]) => (a: A) => Cons(f(a), b))(XList.empty[B])(xs)
Or use type ascription:
def map[A, B](f: A => B)(xs: XList[A]): XList[B] =
reduce((b: XList[B]) => (a: A) => Cons(f(a), b): XList[B])(XList.empty[B])(xs)
As a side note, reduce is traditionally more strict at the method definition than what you've written. reduce usually looks like this:
def reduce[A](a0: A, a: A): A
Implicitly requiring a non empty collection to begin with. What you've implemented is similar in structure to a foldLeft, which has this structure (from Scalas collection library):
def foldLeft[B](z: B)(op: (B, A) => B): B
I tried to implement mergesort in Scala. I got to the following:
def mergeSort[A: Ordering](as: List[A]): List[A] = as match {
case Nil => as
case head :: Nil => as
case _ => {
val (l, r) = split(as)
merge(mergeSort(l), mergeSort(r))
}
}
def split[A](as: List[A]): (List[A], List[A]) = {
def rec(todo: List[A], done: (List[A], List[A])): (List[A], List[A]) = todo match {
case Nil => done
case head :: tail => rec(tail, (head :: done._2, done._1))
}
rec(as, (Nil, Nil))
}
def merge[A: Ordering](left: List[A], right: List[A]) = {
def rec(left: List[A], right: List[A], done: List[A]): List[A] =
(left, right) match {
case (_, Nil) => rprepend(left, done)
case (Nil, _) => rprepend(right, done)
case (lh :: lt, rh :: rt) => if (implicitly[Ordering[A]].compare(lh, rh) <= 0)
rec(lt, right, lh :: done)
else rec(left, rt, rh :: done)
}
rec(left, right, Nil).reverse
}
def rprepend[A](prepend: List[A], as: List[A]): List[A] =
prepend.foldLeft(as)((r, a) => a :: r)
This question is not about the obscene amount of inefficient reversing going on, nor about the lack of tail recursion. Rather, I noticed that you could generalize mergesort by passing in a sort algorithm like so:
def generalizedMergeSort[A: Ordering](as: List[A], sort: List[A] => List[A]): List[A] = as match {
case Nil => as
case head :: Nil => as
case _ => {
val (l, r) = split(as)
merge(sort(l), sort(r))
}
}
Then I tried re-implementing mergesort as
def mergesort[A: Ordering](as: List[A]): List[A] = {
generalizedMergeSort(as, mergesort)
}
but this fails to compile, not finding the proper Ordering[A]:
[error] test.scala:17: No implicit Ordering defined for A.
[error] generalizedMergeSort(as, mergesort)
[error] ^
as a feeble attempt to get things in scope I tried
def mergesort[A: Ordering](as: List[A]): List[A] = {
implicit val realythere = implicitly[Ordering[A]]
generalizedMergeSort(as, mergesort)
}
but to no avail.
I suspect the problem may be in the second parameter of generalizedMergesort. I say the parameter is a List[A] => List[A], but I pass in a List[A] => implicit Ordering[A] => List[A] but I don't know how to make use of that to get to my goal of implementing mergesort in terms of generalizedMergesort and itself.
You can overcome this by passing a function that calls mergesort to generalizedMergeSort. This call will capture the implicit Ordering:
def mergesort[A: Ordering](as: List[A]): List[A] = {
generalizedMergeSort(as, mergesort(_: List[A]))
}
mergesort(_: List[A]) is a closure function of type List[A] => List[A], which calls mergesort with its argument, and the implicit Ordering argument gets captured in this closure.
The simple solution is to extract implicit from method to upper method:
def mergesort[A: Ordering](as: List[A]): List[A] = {
def mergesort0(xs: List[A]): List[A] = generalizedMergeSort(xs, mergesort0)
mergesort0(as)
}
and second is to wrap your function with implicit (with additional object creation):
def mergesort[A: Ordering](as: List[A]): List[A] = {
val mergesort0: List[A] => List[A] = xs => mergesort(xs)
generalizedMergeSort(as, mergesort0)
}
While thinking about my previous question, I realized I ought to be able to write something like the following:
val empty: Try[B, forall types B] = Failure(new RuntimeException("empty"))
def firstSuccess[A, B](xs: Iterable[A], f: A => Try[B]): Try[B] = {
xs.foldLeft(empty)((e, a) => e.recoverWith { case _ => f(a) })
}
because a Failure is a valid Try[B] for any type B. Is there a way to achieve my "B, forall types B" in Scala?
You can use the Nothing type since everything in scala is Nothing:
val empty = Failure[Nothing](new RuntimeException("empty"))
def firstSuccess[A, B](xs: Iterable[A], f: A => Try[B]): Try[B] = {
xs.foldLeft[Try[B]](empty)((e, a) => e.recoverWith { case _ => f(a) })
}
You do have to sprinkle in a few types here and there though (added type parameter to foldLeft).
What is the best way to partition Seq[A \/ B] into (Seq[A], Seq[B]) using Scalaz?
There is a method: separate defined in MonadPlus. This typeclass is a combination a Monad with PlusEmpty (generalized Monoid). So you need to define instance for Seq:
1) MonadPlus[Seq]
implicit val seqmp = new MonadPlus[Seq] {
def plus[A](a: Seq[A], b: => Seq[A]): Seq[A] = a ++ b
def empty[A]: Seq[A] = Seq.empty[A]
def point[A](a: => A): Seq[A] = Seq(a)
def bind[A, B](fa: Seq[A])(f: (A) => Seq[B]): Seq[B] = fa.flatMap(f)
}
Seq is already monadic, so point and bind are easy, empty and plus are monoid operations and Seq is a free monoid
2) Bifoldable[\/]
implicit val bife = new Bifoldable[\/] {
def bifoldMap[A, B, M](fa: \/[A, B])(f: (A) => M)(g: (B) => M)(implicit F: Monoid[M]): M = fa match {
case \/-(r) => g(r)
case -\/(l) => f(l)
}
def bifoldRight[A, B, C](fa: \/[A, B], z: => C)(f: (A, => C) => C)(g: (B, => C) => C): C = fa match {
case \/-(r) => g(r, z)
case -\/(l) => f(l, z)
}
}
Also easy, standard folding, but for type constructors with two parameters.
Now you can use separate:
val seq: Seq[String \/ Int] = List(\/-(10), -\/("wrong"), \/-(22), \/-(1), -\/("exception"))
scala> seq.separate
res2: (Seq[String], Seq[Int]) = (List(wrong, number exception),List(10, 22, 1))
Update
Thanks to Kenji Yoshida, there is a Bitraverse[\/], so you need only MonadPlus.
And a simple solution using foldLeft:
seq.foldLeft((Seq.empty[String], Seq.empty[Int])){ case ((as, ai), either) =>
either match {
case \/-(r) => (as, ai :+ r)
case -\/(l) => (as :+ l, ai)
}
}