I am implementing takeWhile method of trait Stream via foldRight.
My foldRight is following:
trait Stream[+A] {
def foldRight[B](z: => B)(f: (A, => B) => B): B =
uncons.map(t => {
f(t._1, t._2.foldRight(z)(f))
}).getOrElse(z)
}
My takeWhile is
def takeWhile(p: A => Boolean): Stream[A] =
uncons.filter(t => p(t._1)).map(t => Stream.cons(t._1, t._2.takeWhile(p))).getOrElse(Stream.empty)
But I want it to be implemented via foldRight. Here is the code:
def takeWhileViaFoldRight(p: A => Boolean): Stream[A] =
foldRight(Stream.empty)((x, acc) => {
if (p(x)) Stream.cons(x, acc) else Stream.empty
})
But my x in Stream.cons expression is underlined red with the following error: type mismatch; found : x.type (with underlying type A) required: Nothing. I guess this is because foldRight start value is Stream.empty -- with no type A indicated hence considered to be Nothing. If this is the case -- how can I tell foldRight that its return value is A, not Nothing? If not -- what's the problem then?
The courtesy of jdevelop's comment:
foldRight(Stream.empty[A])
will do the thing.
Related
Was playing with Lazy Structure Stream as below
import Stream._
sealed trait Stream[+A] {
..
def toList: List[A] = this match {
case Empty => Nil
case Cons(h, t) => println(s"${h()}::t().toList"); h()::t().toList
}
def foldRight[B](z: B) (f: ( A, => B) => B) : B = this match {
case Empty => println(s"foldRight of Empty return $z"); z
case Cons(h, t) => println(s"f(${h()}, t().foldRight(z)(f))"); f(h(), t().foldRight(z)(f))
}
..
}
case object Empty extends Stream[Nothing]
case class Cons[+A](h: () => A, t: () => Stream[A]) extends Stream[A]
object Stream {
def cons[A](h: => A, t: => Stream[A]): Stream[A] = {
lazy val hd = h
lazy val tl = t
Cons[A](() => hd, () => tl)
}
def empty[A]: Stream[A] = Empty
def apply[A](la: A*): Stream[A] = la match {
case list if list.isEmpty => empty[A]
case _ => cons(la.head, apply(la.tail:_*))
}
}
For a function takeWhile via foldRight i initially wrote:
def takeWhileFoldRight_0(p: A => Boolean) : Stream[A] = {
foldRight(empty[A]) {
case (a, b) if p(a) => println(s"takeWhileFoldRight cons($a, b) with p(a) returns: cons($a, b)"); cons(a, b)
case (a, b) if !p(a) => println(s"takeWhileFoldRight cons($a, b) with !p(a) returns: empty[A]"); empty[A]
}
}
Which when called as:
Stream(4,5,6).takeWhileFoldRight_0(_%2 == 0).toList
result in the following trace:
f(4, t().foldRight(z)(f))
f(5, t().foldRight(z)(f))
f(6, t().foldRight(z)(f))
foldRight of Empty return Empty
takeWhileFoldRight cons(6, b) with p(a) returns: cons(6, b)
takeWhileFoldRight cons(5, b) with !p(a) returns: empty[A]
takeWhileFoldRight cons(4, b) with p(a) returns: cons(4, b)
4::t().toList
res2: List[Int] = List(4)
Then questioning and questioning i figured that it might have been the unapply method in the pattern match that evaluate eagerly.
So i changed to
def takeWhileFoldRight(p: A => Boolean) : Stream[A] = {
foldRight(empty[A]) { (a, b) =>
if (p(a)) cons(a, b) else empty[A]
}
}
which when called as
Stream(4,5,6).takeWhileFoldRight(_%2 == 0).toList
result in the following trace:
f(4, t().foldRight(z)(f))
4::t().toList
f(5, t().foldRight(z)(f))
res1: List[Int] = List(4)
Hence my question:
Is there a way to recover the power of pattern match when working with by-name parameter ?
Said differently case i match parameter that are by-name without evaluating them eagerly ?
Or i have to go to a set of ugly nested "if" :p in that kind of scenario
Take a closer look at this fragment:
def toList: List[A] = this match {
case Empty => Nil
case Cons(h, t) => println(s"${h()}::t().toList"); h()::t().toList
}
def foldRight[B](z: B) (f: ( A, => B) => B) : B = this match {
case Empty => println(s"foldRight of Empty return $z"); z
case Cons(h, t) => println(s"f(${h()}, t().foldRight(z)(f))"); f(h(), t().foldRight(z)(f))
}
..
}
Here h and t in Cons aren't evaluated by unapply - after all unapply returns () => X functions without calling them. But you do. Twice for each match - once for printing and once for passing the result on. And you aren't remembering the result, so any future fold, map, etc would evaluate the function anew.
Depending on what behavior you want to have you should either:
Calculate the results once, right after matching them:
case Cons(h, t) =>
val hResult = h()
val tResult = t()
println(s"${hResult}::tail.toList")
hResult :: tResult.toList
or
not use case class because it cannot memoize the result and you might need to memoize it:
class Cons[A](fHead: () => A, fTail: () => Stream[A]) extends Stream[A] {
lazy val head: A = fHead()
lazy val tail: Stream[A] = fTail()
// also override: toString, equals, hashCode, ...
}
object Cons {
def apply[A](head: => A, tail: => Stream[A]): Stream[A] =
new Cons(() => head, () => tail)
def unapply[A](stream: Stream[A]): Option[(A, Stream[A])] = stream match {
case cons: Cons[A] => Some((cons.head, cons.tail)) // matches on type, doesn't use unapply
case _ => None
}
}
If you understand what you're doing you could also create a case class with overridden apply and unapply (like above) but that is almost always a signal that you shouldn't use a case class in the first place (because most likely toString, equals, hashCode, etc would have nonsensical implementation).
i need some help with this code in scala, i want to implement foldL method but im getting this:
asd.scala:73: error: type mismatch;
found : Option[MyTree[A]] => B
required: B
def myFoldLeft[B](z: B)(op: (B, A) => B): B = (_:Option[MyTree[A]]) match {
^
one error found
I know thats a type missmatch but im newbie with scala and Oriented Object and i dont
understand how to solve this situation.
class MyTree[A](val value: A, val left:Option[MyTree[A]],
val right:Option[MyTree[A]]) {
def myFoldLeft[B](z: B)(op: (B, A) => B): B = (_:Option[MyTree[A]]) match {
case Some(tree) => right.get.myFoldLeft (left.get.myFoldLeft (op(z, value)) (op)) (op)
case None => z
}
}
(_:Option[MyTree[A]]) ... is a lambda.
You should match like
class MyTree[A](val value: A, val left:Option[MyTree[A]],
val right:Option[MyTree[A]]) {
def myFoldLeft[B](z: B)(op: (B, A) => B): B = (left, right) match {
case (Some(left), Some(right)) => ???
case (Some(left), None) => ???
case (None, Some(right)) => ???
case (None, None) => ???
}
}
Working through the excellent "FP in Scala" by Chiusano RĂșnar Bjarnason, had a strange compilation error when trying to implement Stream#takeWhile lazily through #foldRight. Given the following code in the book (also on GitHub):
trait Stream[+A] {
def foldRight[B](z: => B)(f: (A, => B) => B): B =
this match {
case Cons(h,t) => f(h(), t().foldRight(z)(f))
case _ => z
}
case object Empty extends Stream[Nothing]
case class Cons[+A](h: () => A, t: () => Stream[A]) extends Stream[A]
object Stream {
def cons[A](hd: => A, tl: => Stream[A]): Stream[A] = {
lazy val head = hd
lazy val tail = tl
Cons(() => head, () => tail)
def empty[A]: Stream[A] = Empty
}
I tried:
def takeWhile_fold(p: A => Boolean): Stream[A] =
foldRight(empty[A])((it:A, acc:Stream[A]) => if (p(it)) cons(it, acc) else acc)
But this gives the compilation fault:
type mismatch;
[error] found : (A, fpinscala.laziness.Stream[A]) => fpinscala.laziness.Stream[A]
[error] required: (A, => fpinscala.laziness.Stream[A]) => fpinscala.laziness.Stream[A]
[error] foldRight(empty[A])((it:A, acc:Stream[A]) => if (p(it)) cons(it, acc) else ac
But if I remove the types on the lambda, it works:
def takeWhile_fold(p: A => Boolean): Stream[A] =
foldRight(empty[A])((it, acc) => if (p(it)) cons(it, acc) else acc)
There is no way in Scala to state in the calling code that it should be a by-name parameter, is there? (Does it even make sense for the caller, it is the receiver that decides, right?) Attempting:
def takeWhile_fold(p: A => Boolean): Stream[A] =
foldRight(empty[A])((it, acc: => Stream[A]) => if (p(it)) cons(it, acc) else acc)
Gives another compilation error:
[error] identifier expected but '=>' found.
[error] foldRight(empty[A])((it, acc: => Stream[A]) => if (p(it)) cons(it, acc) else acc)
^
[error] ')' expected but '}' found.
[error] }
[error] ^
[error] two errors found
I've solved the exercise, but my questions are - why doesn't it work with explicit types? Do they enforce strictness somehow while the receiver must have non-strict? And if so, is there any syntax in Scala so the caller can signal that "yes, this is by-name parameters"?
Yes, by-name ends up being part of the signature. You can imagine that by-name parameters are implemented by the compiler by translating this:
def foo(n: => Int) = ... n ...
to this:
def foo(n: () => Int) = ... n() ...
A side effect of this is that, if you reference by-name parameters multiple times, they will be evaluated multiple times. So this:
def bar(n: => Int) = n + n
bar( { println("foo"); 5 } )
Will print foo twice before returning 10. It's the same as this:
def bar(n: () => Int) = n() + n()
bar { () => println("foo"); 5 }
As for whether you can explicitly state that a lambda takes by-name parameters... I'm not sure. I tried this:
def foo( f: ( => Int) => Int ) = f({ println("foo"); 5 })
foo { (a) => a + a }
Which worked. I tried these:
foo { (a : Int ) => a + a }
foo { (a : => Int ) => a + a }
Which failed.
The spec seems to indicate that the type property of formal parameters to functions are generated with the ParamType syntax rule, whereas the type property of anonymous functions parameters uses the plain Type rule. And the => by-name indicator is on ParamType.
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).
I am following the book Functional programming in Scala and in particular the section where you implement a simple Stream trait and companion object. For reference, here is what we have so far in the companion obejct
object Stream {
def empty[A]: Stream[A] =
new Stream[A] {
def uncons = None
}
def cons[A](hd: => A, tl: => Stream[A]): Stream[A] =
new Stream[A] {
lazy val uncons = Some((hd, tl))
}
def apply[A](as: A*): Stream[A] =
if (as.isEmpty)
empty
else
cons(as.head, apply(as.tail: _*))
}
and the trait so far:
trait Stream[A] {
import Stream._
def uncons: Option[(A, Stream[A])]
def toList: List[A] = uncons match {
case None => Nil: List[A]
case Some((a, as)) => a :: as.toList
}
def #::(a: => A) = cons(a, this)
def take(n: Int): Stream[A] =
if (n <= 0)
empty
else (
uncons
map { case (a, as) => a #:: (as take (n - 1)) }
getOrElse empty
)
}
The next exercise requires me to write an implementation for takeWhile and I thought the following would do
def takeWhile(f: A => Boolean): Stream[A] = (
uncons
map { case (a, as) => if (f(a)) (a #:: (as takeWhile f)) else empty }
getOrElse empty
)
Unfortunately, is seems that I get a variance error that I am not able to track down:
error: type mismatch; found : Stream[_2] where type _2 <: A
required: Stream[A]
Note: _2 <: A, but trait Stream is invariant in type A.
You may wish to define A as +A instead. (SLS 4.5)
getOrElse empty
^
I could add a variance annotation, but before doing that I would like to understand what is going wrong here. Any suggestions?
this seems to be an issue with type inference, because it works if you explicitly specify the type of the subexpression uncons map { case (a, as) => if (f(a)) (a #:: (as takeWhile f)) else empty }.
def takeWhile(f: A => Boolean): Stream[A] = {
val mapped:Option[Stream[A]] = uncons map {
case (a, as) => if (f(a)) (a #:: (as takeWhile f)) else empty
}
mapped getOrElse empty
}
To complete a bit the other answer, the empty on this line:
map { case (a, as) => if (f(a)) (a #:: (as takeWhile f)) else empty }
is inferred as empty[Nothing], which means that (a #:: (as takeWhile f)) else empty is inferred as Stream[Foo <: A] and since a Stream[A] is expected and Stream is invariant, you have an error.
So this gives us the cleanest way to fix this: just annotate empty:
map { case (a, as) => if (f(a)) (a #:: (as takeWhile f)) else empty[A] }
And then it compiles fine.
This does not happen with the original Stream because it is covariant, so either you actually want Stream.empty to be a Stream[Nothing] (just like Nil is a List[Nothing]), or you don't care.
Now, as to exactly why it is inferred as empty[Nothing] and not empty[A], this is probably hidden somewhere in SLS 6.26.4 "Local Type Inference", but this part cannot really be accused of being easy to read...
As a rule a thumb, always be suspicious whenever you call methods:
that have type parameters whose only way to infer is the expected return type (usually because they have no arguments),
AND at the same time the expected return type is itself supposed to be inferred from somewhere else.