How does pattern matching work in exists function? - scala

This code from book "Functional programming in scala"
sealed 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
}
def exists(p: A => Boolean): Boolean = foldRight(false)((a, b) => p(a) || b)
}
case object Empty extends Stream[Nothing]
case class Cons[+A](h: () => A, t: () => Stream[A]) extends Stream[A]
I don't understand what is it a and b in exists func? How scala match arguments to foldRight

The foldRight and foldLeft operates over a collection (stream in your example), receives two parameters (base value) and a function. This function receives also two parameters an accumulator and a element, which process in each iteration
The accumulator is in the side of the fold (i.e. to the right in foldRight and to the left in foldLeft), so in your case b is the accumulator.
The accumulator is initialized as the default value (false in your example)
The other parameter (a in your example) is each element of the stream over which you iterate.
In this case (exists) will iterate until an element satisfied the predicate p, otherwise it will keep iterating until it reaches the end of the Stream
From the API
def foldRight[B](z: B)(op: (A, B) ⇒ B): B Applies a binary operator to
all elements of this sequence and a start value, going right to left.
Note: will not terminate for infinite-sized collections.
B the result type of the binary operator.
z the start value.
op the binary operator.
returns the result of inserting op between consecutive elements of
this sequence, going right to left with the start value z on the
right:
op(x_1, op(x_2, ... op(x_n, z)...)) where x1, ..., xn are the elements
of this sequence. Returns z if this sequence is empty.
You can check the whole API here

Always check the excellent ScalaAPI (http://lampwww.epfl.ch/~hmiller/scaladoc/library/scala/collection/TraversableOnce.html)
def foldRight[B](z: B)(op: (A, B) ⇒ B): B
From the types you can figure it out:
a -> A
b -> B
As you have a Stream of type A (sealed trait Stream[+A]) a can only be one of the elements of the Stream.
b is so the value you are accumulating the result on. In exists it checks if one element is true for the predicate p.

Related

Scala - Map2 function on Option --> flatMap vs. Map vs. For-Comprehension

Option is used for dealing with partiality in Scala, but we can also lift ordinary functions to the context of Options in order to handle errors. When implementing the function map2 I am curious on how to know when to use which functions. Consider the following implementation:
def map2[A,B,C] (ao: Option[A], bo: Option[B]) (f: (A,B) => C): Option[C] =
ao flatMap {aa =>
bo map {bb =>
f(aa, bb)
aa is of type A, and bb is of type B which is then fed to F, giving us a C. However, if we do the following:
def map2_1[A,B,C] (ao: Option[A], bo: Option[B]) (f: (A,B) => C): Option[C] =
ao flatMap {aa =>
bo flatMap {bb =>
f(aa, bb)
aa is still of type A, and bb is still of type B, yet we will have to wrap the last call in Some(f(aa, bb)) in order to get an Option[C] instead of a regular C. Why is this? What does it mean to flatten on BO here?
Last and not least, one could do the simpler:
def map2_2[A,B,C] (ao: Option[A], bo: Option[B]) (f: (A,B) => C): Option[C] = for {
as <- ao
bs <- bo
} yield(f(as,bs))
I know that for-comprehensions are syntactic sugar for ForEach'es, maps and flatmaps etc, but how do I, as a developer, know that the compiler will choose MAP with bs <- bo, and not flatMap?
I think I am on the verge of understanding the difference, yet nested flatmaps confuse me.
Taking the last question first, the developer knows what the compiler will do with for because the behaviour is defined and predictable: All <- turn into flatMap except the last one which will be either map or foreach depending on whether or not there is a yield.
The broader question seems to be about the difference between map and flatMap. The difference should be clear from the signatures e.g. for List these are the (simplified) signatures:
def map[B] (f: A => B) : List[B]
def flatMap[B](f: A => List[B]): List[B]
So map just replaces the values in a List with new values by applying f to each element of type A to generate a B.
flatMap generates a new list by concatenating the results of calling f on each element of the original List. It is equivalent to map followed by flatten (hence the name).
Intuitively, map is a one-for-one replacement whereas flatMap allows each element in the original List to generate 0 or more new elements.

Scala - Rule to infer the variable on the right hand side

I tried to do research but still not yet figure out what is the terminology of Scala, related to lower case a,b as per the code below
def curry[A, B, C](f: (A, B) => C): A => (B => C) = a => b => f(a, b)
Why is that a,b appears on the right hand side?
I know that it is a part of Algebraic Data Type but still could not find a match definition for this.
Update based on Tim's answer, "Scala knows the type of a and b from the return type A => (B => C). a is type A, b is type B."
I want to ask about how Scala knows the type of a and b, i.e: the mechanism behind? What is the terminology of this?
I guess this is a language feature. Please suggest a foundation guideline to fully understand and practice to gain intuition when reading these complex code.
Update from Mario Galic's comment: ... Scala compiler can perform type inference based on the signature of curry ... Please clarify: if the left hand side (i.e the signature) is too obvious, why we need to have the right hand side definition? I mean, there is only 1 way to infer the logic of the left hand side, then, what is the need of creating the right hand side content?
P/S: I wish that I could mark each feedback as the answer because each provides different aspect which helps me to fully grasp the meaning.
It might help to add full type annotations
def curry[A, B, C](f: (A, B) => C): A => (B => C) =
(a: A) => ((b: B) => f(a, b): C)
Note how curry is a method that takes a function as input and also returns a function as output. You might be wondering where do a and b come from in the output function
(a: A) => ((b: B) => f(a, b): C)
but note that they are just the means of declaring the parameters of the output function. You are free to give them any name, for example the following would also work
(x: A) => ((y: B) => f(x, y): C)
The key is to understand that functions are first class values in Scala, so you can pass them in as arguments to other functions and return them as return values from other functions, in the same way you would do with familiar values like say integer 42. Writing value 42 is straightforward, but writing down function value is more verbose since you have to specify the parameters like a and b but nevertheless conceptually it is still just a value. Hence we could say curry is a method that takes a value and returns a value, but these values happen to be function values.
As we all know, it's pretty easy to create a tuple: (1,'a'). And the type of said tuple is pretty simple: (Int,Char). That type designation, however, is a convenient alternative for the more verbose type designation Tuple2[Int,Char]. In fact, the tuple creation itself is a convenient alternate syntax to the more direct new Tuple2(1,'a').
It's a similar story with functions.
The type designation Char => Int is a convenient alternative to the more verbose Function1[Char,Int]. And, after studying the ScalaDocs page, we learn that a simple function like...
val ctoi = (c:Char) => c.toInt
...is the equivalent of...
val ctoi = new Function1[Char, Int] {
def apply(c: Char): Int = c.toInt
}
So, armed with this information, we can now translate...
def curry[A,B,C](f: (A, B) => C): A => (B => C) =
a => b => f(a, b)
...into its equivalent...
def curry[A,B,C](f: Function2[A,B,C]): Function1[A,Function1[B,C]] =
new Function1[A,Function1[B,C]] {
def apply(a:A) = new Function1[B,C] {def apply(b:B) = f(a,b)}
}
With this it's a little easier to see how a => b => ..., while a bit confusing at first, is actually a very convenient way to designate the names of the arguments being passed in to the hidden apply() methods.
The question doesn't really make sense, but in case this helps here is a breakdown of that line:
def curry[A, B, C](f: (A, B) => C): A => (B => C) = a => b => f(a, b)
This splits into a definition and an implementation with = inbetween. The definition is
def curry[A, B, C](f: (A, B) => C): A => (B => C)
Breaking it down further, A, B, and C are type parameters, meaning that any three types can be used when calling this function.
Next comes the single argument to the function:
f: (A, B) => C
The value of this argument is a function that takes two values (one of type A and one of type B) are returns a single value of type C.
Next comes the type of the result:
A => (B => C)
This is a function that takes a single argument of type A and returns a function that takes a single argument of type B and returns a result of type C.
So curry is a function that takes a function of type (A, B) => C) and returns a function of type A => (B => C). This implements the process known as currying (hence the name).
Now for the implementation (the other side of the =):
a => b => f(a, b)
Adding some brackets might make this clearer:
a => (b => f(a, b))
This is a function that take a and returns b => f(a, b). a is the argument for this function. So that leaves this
b => f(a, b)
This is a simple function with an argument b that returns f(a, b).
Scala knows the type of a and b from the return type A => (B => C). a is type A, b is type B.

Why does this function parameter need double braces on a tuple?

Note: I am using scalac. Please do not recommend to use sbt instead.
I ran into a peculiar issue that I could resolve, but I am wondering why it works that way and not the way I did it before. Here's a code snippet:
def multiply[A](r1: Vector[A], r2: Vector[A], multOp: (A,A) => A, sumOp: (A, A) => A) =
r1.zip(r2).map(multOp).reduce(sumOp)
It does not compile, resulting in an error message like:
Error:(73, 20) type mismatch;
found : (A, A) => A
required: ((A, A)) => ?
r1.zip(r2).map(multOp).reduce(sumOp)
Changing the snippet to:
def multiply[A](r1: Vector[A], r2: Vector[A], multOp: ((A,A)) => A, sumOp: (A, A) => A) =
r1.zip(r2).map(multOp).reduce(sumOp)
will resolve the issue.
Note that sumOp does work with only one pair of braces.
Why?
Method map is defined as taking a single parameter, and (A, A) => A has two. By converting two parameters of type A into one parameter which is a tuple of type (A, A), it compiles.
(A, A) => A // fails due to two params of type A
((A, A)) => A // works due to one param of type (A, A)
On the other hand, reduce is defined as taking two parameters of the same type, so it's happy to take sumOp which matches that description.
Here are the full signatures found in TraversableLike and TraversableOnce respectively:
def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Repr, B, That]): That
def reduce[A1 >: A](op: (A1, A1) => A1): A1
EDIT (extra info):
Reason for this is the fact that reduce always takes a 2-arity function (that is, a function of two parameters) in order to reduce the collection to a single value by iteratively applying that function on the result of previous application and the next value. On the other hand, map always takes a 1-arity function and it maps the underlying value with that function. In case of Option, Future, etc. there's only one single underlying value, while in case of a Vector (like yours) there can be many, so it applies it to every element of the collection.
In some libraries you might come across map2 which takes a two-parameter function. For example, in order to combine two Options (actually, any applicative functors, but let's leave theory aside), you might do:
// presudocode
Option(1, 2).map2((a, b) => a + b)
which would give you an Option(3). I think this mechanism has been dropped in the favour of more easily understandable map + product
// presudocode
(Option(1) product Option(2)) map ((a, b) => a + b)
Actual scalaz syntax for the line above would be (in Scalaz 7):
(Option(1) |#| Option(2))((a, b) => a + b)
They are equally powerful principles (what one can do, exactly the same other one can do, no more, no less) so the latter one is usually preferred and sometimes it's the only one provided, but yes, you might come across map2 from time to time.
Alright, that's a bit of extra info. As far as map is concerned, just remember there's always just one single parameter coming in and one value coming out.
The first snippet will work, if you define it as:
def multiply[A](r1: Vector[A], r2: Vector[A], multOp: (A,A) => A, sumOp: (A, A) => A) =
(r1, r2).zipped.map(multOp).reduce(sumOp)
The map method of a zipped tuple takes a function with two arguments (A, A) => B, because that's the expected usage pattern.
This approach also avoids the creation of an intermediate Vector[(A, A)].

Why is fold curried?

Could start value just be a parameter in op argument list ?
Food is defined on List as
def fold[A1 >: A](z: A1)(op: (A1, A1) ⇒ A1): A1 Folds the elements
of this traversable or iterator using the specified associative binary
operator.
What would the implications of defining fold as
def fold[A1 >: A](op: (z:A1,A1, A1) ⇒ A1): A1
So in this version the initial value is passed as a value to the function instead of being curried in a separate parameter list.
If you're looking to motivate that particular signature of foldLeft, it may be worthwhile to first examine reduceLeft.
// Slightly simplified to remove the supertype constraint
def reduceLeft(f: (A, A) => A): A
reduceLeft squishes the entire collection into a single element and it takes as an argument a function that tells it how to squish each new element in the collection onto what it's got so far.
There's, however, a problem. reduceLeft is partial. In particular if the collection is empty, reduceLeft has nowhere to begin squishing things. So we can make it total, by telling reduceLeft where to begin. So we give reduceLeft an additional parameter.
def reduceLeftTotal(initial: A, f: (A, A) => A): A
Note that if we just glommed initial as another argument to f, we wouldn't fix the partiality of reduceLeft. If this is an empty collection, we still blow up.
// This doesn't get us what we want. Where does the initial `A` come from?
def reduceLeftNotWhatWeWant(f: (A, A, A) => A): A
Okay, now that we've got reduceLeftTotal, there's an immediate new avenue for generalization. Why does the thing that we're squishing all the elements of our collection onto have to have the same type as the elements? The answer is it doesn't!
def generalReduceLeftTotal[B](initial: B, f: (B, A) => A): B
Finally because type information in previous argument lists, but not previous arguments in the same list, can be used to help Scala's type inference, we can reduce the amount of explicit type annotations we need by currying.
// And we're back to foldLeft!
def foldLeft[B](initial: B)(f: (B, A) => A): B

Fold method using List as accumulator

To find prime factors of a number I was using this piece of code :
def primeFactors(num: Long): List[Long] = {
val exists = (2L to math.sqrt(num).toLong).find(num % _ == 0)
exists match {
case Some(d) => d :: primeFactors(num/d)
case None => List(num)
}
}
but this I found a cool and more functional approach to solve this using this code:
def factors(n: Long): List[Long] = (2 to math.sqrt(n).toInt)
.find(n % _ == 0).fold(List(n)) ( i => i.toLong :: factors(n / i))
Earlier I was using foldLeft or fold simply to get sum of a list or other simple calculations, but here I can't seem to understand how fold is working and how this is breaking out of the recursive function.Can somebody plz explain how fold functionality is working here.
Option's fold
If you look at the signature of Option's fold function, it takes two parameters:
def fold[B](ifEmpty: => B)(f: A => B): B
What it does is, it applies f on the value of Option if it is not empty. If Option is empty, it simply returns output of ifEmpty (this is termination condition for recursion).
So in your case, i => i.toLong :: factors(n / i) represents f which will be evaluated if Option is not empty. While List(n) is termination condition.
fold used for collection / iterators
The other fold that you are taking about for getting sum of collection, comes from TraversableOnce and it has signature like:
def foldLeft[B](z: B)(op: (B, A) => B): B
Here, z is starting value (suppose incase of sum it's 0) and op is associative binary operator which is applied on z and each value of collection from left to right.
So both folds differ in their implementation.