Inline function ambiguity in Scala - scala

When passing an operator lifted to be a function to one of defined higher order functions, Scala allows for very concise syntax, e.g (please ignore the fact that it can be simplified to .product()):
List(1,2,3).fold(1)(_ * _)
To the above I can just pass _ \* _
However having defined my own toy function zipWith(), I need to be very explicit when passing a function:
implicit class EnrichedList[A](val self: List[A]) extends AnyVal {
def zipWith[B, C](that: List[B])
(implicit zipper: A => B => C): List[C] = {
def zipWithHelper(zipper: A => B => C)
(as: List[A])
(bs: List[B]): List[C] = {
(as, bs) match {
case (_, Nil) => Nil
case (Nil, _) => Nil
case (a :: restOfA, b :: restOfB) =>
zipper(a)(b) :: zipWithHelper(zipper)(restOfA)(restOfB)
}
}
zipWithHelper(zipper)(self)(that)
}
}
This: List(1, 3, 4).zipWith(List(3, 4, 5))(_ * _) will not work, saying
Error:(60, 46) missing parameter type for expanded function ((x$1: , x$2) => x$1.$times(x$2))
List(1, 3, 4).zipWith(List(3, 4, 5))(_ * _)
I need to say what type of arguments function takes:
List(1, 3, 4).zipWith(List(3, 4, 5))((x: Int) => (y: Int) => x * y)
Why won't the compiler allow me just to pass in a shorthand version _ * _?

The expression _ * _ is not shorthand for (x: Int) => (y: Int) => x * y. It's a shorthand for (x: Int, y: Int) => x * y. If you change the type of zipper to (A, B) => C instead of A => B => C, it should work. Currying is a thing, it's not just a fancy name for an identity function.
This here compiles:
implicit class EnrichedList[A](val self: List[A]) {
def zipWith[B, C](that: List[B])
(implicit zipper: (A, B) => C): List[C] = {
def zipWithHelper(zipper: (A, B) => C)
(as: List[A])
(bs: List[B]): List[C] = {
(as, bs) match {
case (_, Nil) => Nil
case (Nil, _) => Nil
case (a :: restOfA, b :: restOfB) =>
zipper(a, b) :: zipWithHelper(zipper)(restOfA)(restOfB)
}
}
zipWithHelper(zipper)(self)(that)
}
}
println( List(1, 3, 4).zipWith(List(3, 4, 5))(_ * _) )
and prints
List(3, 12, 20)

Related

Is it possible to pattern match on a by-name parameter without evaluating it?

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).

zipWith in Scala using map

Define zipWith. It should zip two lists, but instead of zipping elements into a tuple,
it should use a function to combine two elements.
Example: zipWith(List(1, 2, 3),
List(10, 11, 12),
(x: Int, y: Int) => x+y)
Should return: List(11,13,15)
use map and zip.
def zipWith[A,B,C](xs: List[A], ys: List[B], f: (A, B) => C): List[C] = {
val zs = xs.zip(ys)
//I don't know how to do this because if myMap(zs, f)
//myMap takes a functin f:(a)=>b instead of f: (A, B) => C
}
}
It sounds like you looking for something like this:
def zipWith[A,B,C](xs: List[A], ys: List[B], f: (A, B) => C): List[C] = {
(xs, ys) match {
case (Nil, _) => Nil
case (_, Nil) => Nil
case (x :: xs, y :: ys) => f(x, y) :: zipWith(xs, ys, f)
}
}
Hope that helps.
Update
Here is the same function but being tail-recursive:
def zipWith[A, B, C](xs: List[A], ys: List[B], f: (A, B) => C): List[C] = {
#tailrec
def zipAccumulatingResult(xs: List[A], ys: List[B], f: (A, B) => C, acc: List[C]): List[C] = {
(xs, ys) match {
case (Nil, _) => acc
case (_, Nil) => acc
case (x :: xs, y :: ys) => zipAccumulatingResult(xs, ys, f, acc :+ f(x, y))
}
}
zipAccumulatingResult(xs, ys, f, Nil)
}

Scala foldLeft while some conditions are true

How to emulate following behavior in Scala? i.e. keep folding while some certain conditions on the accumulator are met.
def foldLeftWhile[B](z: B, p: B => Boolean)(op: (B, A) => B): B
For example
scala> val seq = Seq(1, 2, 3, 4)
seq: Seq[Int] = List(1, 2, 3, 4)
scala> seq.foldLeftWhile(0, _ < 3) { (acc, e) => acc + e }
res0: Int = 1
scala> seq.foldLeftWhile(0, _ < 7) { (acc, e) => acc + e }
res1: Int = 6
UPDATES:
Based on #Dima answer, I realized that my intention was a little bit side-effectful. So I made it synchronized with takeWhile, i.e. there would be no advancement if the predicate does not match. And add some more examples to make it clearer. (Note: that will not work with Iterators)
First, note that your example seems wrong. If I understand correctly what you describe, the result should be 1 (the last value on which the predicate _ < 3 was satisfied), not 6
The simplest way to do this is using a return statement, which is very frowned upon in scala, but I thought, I'd mention it for the sake of completeness.
def foldLeftWhile[A, B](seq: Seq[A], z: B, p: B => Boolean)(op: (B, A) => B): B = foldLeft(z) { case (b, a) =>
val result = op(b, a)
if(!p(result)) return b
result
}
Since we want to avoid using return, scanLeft might be a possibility:
seq.toStream.scanLeft(z)(op).takeWhile(p).last
This is a little wasteful, because it accumulates all (matching) results.
You could use iterator instead of toStream to avoid that, but Iterator does not have .last for some reason, so, you'd have to scan through it an extra time explicitly:
seq.iterator.scanLeft(z)(op).takeWhile(p).foldLeft(z) { case (_, b) => b }
It is pretty straightforward to define what you want in scala. You can define an implicit class which will add your function to any TraversableOnce (that includes Seq).
implicit class FoldLeftWhile[A](trav: TraversableOnce[A]) {
def foldLeftWhile[B](init: B)(where: B => Boolean)(op: (B, A) => B): B = {
trav.foldLeft(init)((acc, next) => if (where(acc)) op(acc, next) else acc)
}
}
Seq(1,2,3,4).foldLeftWhile(0)(_ < 3)((acc, e) => acc + e)
Update, since the question was modified:
implicit class FoldLeftWhile[A](trav: TraversableOnce[A]) {
def foldLeftWhile[B](init: B)(where: B => Boolean)(op: (B, A) => B): B = {
trav.foldLeft((init, false))((a,b) => if (a._2) a else {
val r = op(a._1, b)
if (where(r)) (op(a._1, b), false) else (a._1, true)
})._1
}
}
Note that I split your (z: B, p: B => Boolean) into two higher-order functions. That's just a personal scala style preference.
What about this:
def foldLeftWhile[A, B](z: B, xs: Seq[A], p: B => Boolean)(op: (B, A) => B): B = {
def go(acc: B, l: Seq[A]): B = l match {
case h +: t =>
val nacc = op(acc, h)
if(p(nacc)) go(op(nacc, h), t) else nacc
case _ => acc
}
go(z, xs)
}
val a = Seq(1,2,3,4,5,6)
val r = foldLeftWhile(0, a, (x: Int) => x <= 3)(_ + _)
println(s"$r")
Iterate recursively on the collection while the predicate is true, and then return the accumulator.
You cand try it on scalafiddle
After a while I received a lot of good looking answers. So, I combined them to this single post
a very concise solution by #Dima
implicit class FoldLeftWhile[A](seq: Seq[A]) {
def foldLeftWhile[B](z: B)(p: B => Boolean)(op: (B, A) => B): B = {
seq.toStream.scanLeft(z)(op).takeWhile(p).lastOption.getOrElse(z)
}
}
by #ElBaulP (I modified a little bit to match comment by #Dima)
implicit class FoldLeftWhile[A](seq: Seq[A]) {
def foldLeftWhile[B](z: B)(p: B => Boolean)(op: (B, A) => B): B = {
#tailrec
def foldLeftInternal(acc: B, seq: Seq[A]): B = seq match {
case x :: _ =>
val newAcc = op(acc, x)
if (p(newAcc))
foldLeftInternal(newAcc, seq.tail)
else
acc
case _ => acc
}
foldLeftInternal(z, seq)
}
}
Answer by me (involving side effects)
implicit class FoldLeftWhile[A](seq: Seq[A]) {
def foldLeftWhile[B](z: B)(p: B => Boolean)(op: (B, A) => B): B = {
var accumulator = z
seq
.map { e =>
accumulator = op(accumulator, e)
accumulator -> e
}
.takeWhile { case (acc, _) =>
p(acc)
}
.lastOption
.map { case (acc, _) =>
acc
}
.getOrElse(z)
}
}
Fist exemple: predicate for each element
First you can use inner tail recursive function
implicit class TravExt[A](seq: TraversableOnce[A]) {
def foldLeftWhile[B](z: B, f: A => Boolean)(op: (A, B) => B): B = {
#tailrec
def rec(trav: TraversableOnce[A], z: B): B = trav match {
case head :: tail if f(head) => rec(tail, op(head, z))
case _ => z
}
rec(seq, z)
}
}
Or short version
implicit class TravExt[A](seq: TraversableOnce[A]) {
#tailrec
final def foldLeftWhile[B](z: B, f: A => Boolean)(op: (A, B) => B): B = seq match {
case head :: tail if f(head) => tail.foldLeftWhile(op(head, z), f)(op)
case _ => z
}
}
Then use it
val a = List(1, 2, 3, 4, 5, 6).foldLeftWhile(0, _ < 3)(_ + _)
//a == 3
Second example: for accumulator value:
implicit class TravExt[A](seq: TraversableOnce[A]) {
def foldLeftWhile[B](z: B, f: A => Boolean)(op: (A, B) => B): B = {
#tailrec
def rec(trav: TraversableOnce[A], z: B): B = trav match {
case _ if !f(z) => z
case head :: tail => rec(tail, op(head, z))
case _ => z
}
rec(seq, z)
}
}
Or short version
implicit class TravExt[A](seq: TraversableOnce[A]) {
#tailrec
final def foldLeftWhile[B](z: B, f: A => Boolean)(op: (A, B) => B): B = seq match {
case _ if !f(z) => z
case head :: tail => tail.foldLeftWhile(op(head, z), f)(op)
case _ => z
}
}
Simply use a branch condition on the accumulator:
seq.foldLeft(0, _ < 3) { (acc, e) => if (acc < 3) acc + e else acc}
However you will run every entry of the sequence.

What is wrong with use of lambda here

I wrote map1 function similar to List.map as:
def map1[A, B](xs: List[A], f: A => B): List[B] = {
xs match {
case List() => scala.collection.immutable.Nil
case head :: tail => f(head) :: map1(tail, f)
}
}
Now when I call the above as:
map1(List(1, 2, 3), x => x + 1)
I get error as: error: missing parameter type. But following works:
List(1, 2, 3).map(x => x + 1)
Why map1 doesn't work with lamdas?
In Scala, argument type inference works between argument lists and not inside them. To help the compiler infer the type, move f to it's own argument list:
def map1[A, B](xs: List[A])(f: A => B): List[B] = {
xs match {
case Nil => scala.collection.immutable.Nil
case head :: tail => f(head) :: map1(tail)(f)
}
}

Scala really weird Type Mismatch

I'm trying to implement dropWhile in Scala but I get a type mismatch, on the invocation of "f(h)" error that says it actually found the type it was expecting:
def dropWhile[A](l: XList[A])(f: A => Boolean): XList[A] = {
def dropWhile[A](toCheck: XList[A], toKeep: XList[A]) : XList[A] = toCheck match {
case XNil => toKeep
case Cons(h, t) if **f(h)** == false => dropWhile(tail(toCheck), Cons(h, toKeep))
case Cons(_, Cons(t1, t2)) => dropWhile(Cons(t1, t2), toKeep)
}
dropWhile(l, XList[A]())
}
error message:
found : h.type (with underlying type A)
[error] required: A
relevant code:
sealed trait XList[+A] {}
case object XNil extends XList[Nothing]
case class Cons[+A](head: A, tail: XList[A]) extends XList[A]
EDIT:
Here's a way to make it compile - but the winning answer is better and explains why as well.
def dropWhile[A](l: XList[A])(f: A => Boolean): XList[A] = {
#tailrec
def dropWhile[A](toCheck: XList[A], toKeep: XList[A], dropItem: A => Boolean): XList[A] = toCheck match {
case Cons(h, XNil) if !dropItem(h) => Cons(h, toKeep)
case Cons(h, XNil) if dropItem(h) => toKeep
case Cons(h, t) if !dropItem(h) => dropWhile(t, Cons(h, toKeep), dropItem)
case Cons(h, t) if dropItem(h) => dropWhile(t, toKeep, dropItem)
}
dropWhile(l, XList[A](), f)
}
You already have type parameter A on the original 'dropWhile' which is scoping the type of f. However, you then introduce a second type parameter on the inner def which shadows the outer definition of A and scopes the type of the XList. So the problem is that the A are not the same type! If you remove the shadowed type, it all works (few other changes made to get your code to compile):
def dropWhile[A](l: XList[A])(f: A => Boolean): XList[A] = {
def dropWhile(toCheck: XList[A], toKeep: XList[A]) : XList[A] = toCheck match {
case XNil => toKeep
case Cons(h, t) if f(h) == false => dropWhile(t, Cons(h, toKeep))
case Cons(_, Cons(t1, t2)) => dropWhile(Cons(t1, t2), toKeep)
}
dropWhile(l, XNil)
}
You could just use a foldRight instead (I've simplified this to use List rather than XList):
scala> def dropWhile[A](l: List[A])(f: A => Boolean): List[A] =
| l.foldRight(List[A]())((h,t) => if (f(h)) t else h :: t)
dropWhile: [A](l: List[A])(f: A => Boolean)List[A]
scala> val l = List(1,2,3,4,5,6,5,4,3,2,1)
l: List[Int] = List(1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1)
scala> l.dropWhile(_ < 4)
res1: List[Int] = List(4, 5, 6, 5, 4, 3, 2, 1)
Doesn't answer your found : h.type (with underlying type A) question though :-)