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)
}
}
Related
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) => ???
}
}
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)
The test("ok") is copied from book "scala with cats" by Noel Welsh and Dave Gurnell pag.254 ("D.4 Safer Folding using Eval
"), the code run fine, it's the trampolined foldRight
import cats.Eval
test("ok") {
val list = (1 to 100000).toList
def foldRightEval[A, B](as: List[A], acc: Eval[B])(fn: (A, Eval[B]) => Eval[B]): Eval[B] =
as match {
case head :: tail =>
Eval.defer(fn(head, foldRightEval(tail, acc)(fn)))
case Nil =>
acc
}
def foldRight[A, B](as: List[A], acc: B)(fn: (A, B) => B): B =
foldRightEval(as, Eval.now(acc)) { (a, b) =>
b.map(fn(a, _))
}.value
val res = foldRight(list, 0L)(_ + _)
assert(res == 5000050000l)
}
The test("ko") returns same values of test("ok") for small list but for long list the value is different. Why?
test("ko") {
val list = (1 to 100000).toList
def foldRightSafer[A, B](as: List[A], acc: B)(fn: (A, B) => B): Eval[B] = as match {
case head :: tail =>
Eval.defer(foldRightSafer(tail, acc)(fn)).map(fn(head, _))
case Nil => Eval.now(acc)
}
val res = foldRightSafer(list, 0)((a, b) => a + b).value
assert(res == 5000050000l)
}
This is #OlegPyzhcov's comment, converted into a community wiki answer
You forgot the L in 0L passed as second argument to foldRightSafer.
Because of that, the inferred generic types of the invocation are
foldRightSafer[Int, Int]((list : List[Int]), (0: Int))((_: Int) + (_: Int))
and so your addition overflows and gives you something smaller than 2000000000 (9 zeroes, Int.MaxValue = 2147483647).
I am having trouble understanding the solution to the functional programming exercise:
Implement flatMap using only foldRight, Nil and :: (cons).
The solution is as follows:
def flatMap[A, B](xs: List[A])(f: A => List[B]): List[B] =
xs.foldRight(List[B]())((outCurr, outAcc) =>
f(outCurr).foldRight(outAcc)((inCurr, inAcc) => inCurr :: inAcc))
I have tried to factor out anonymous functions into function definitions to rewrite the solution to no luck. I cannot understand what is happening or think of a way to break it down so it's less complicated. So, any help or explanation regarding the solution would be appreciated.
Thanks!
First, just ignore the constraints and think about the flatMap function in this case. You have a List[A] and a function f: A => List[B]. Normally, if you just do a map on the list and apply the f function, you'll get back a List[List[B]], right? So to get a List[B], what would you do? You would foldRight on the List[List[B]] to get back a List[B] by just appending all elements in the List[List[B]]. So the code will look somewhat like this:
def flatMap[A, B](xs: List[A])(f: A => List[B]): List[B] = {
val tmp = xs.map(f) // List[List[B]]
tmp.foldRight(List[B]())((outCurr, outAcc) => outCurr ++ outAcc)
}
To verify what we have so far, running the code in REPL and verify the result against built-in flatMap method:
scala> def flatMap[A, B](xs: List[A])(f: A => List[B]): List[B] = {
| val tmp = xs.map(f) // List[List[B]]
| tmp.foldRight(List[B]())((outCurr, outAcc) => outCurr ++ outAcc)
| }
flatMap: [A, B](xs: List[A])(f: A => List[B])List[B]
scala> flatMap(List(1, 2, 3))(i => List(i, 2*i, 3*i))
res0: List[Int] = List(1, 2, 3, 2, 4, 6, 3, 6, 9)
scala> List(1,2,3).flatMap(i => List(i, 2*i, 3*i))
res1: List[Int] = List(1, 2, 3, 2, 4, 6, 3, 6, 9)
OK, so now, look at our constraints, we are not allowed to use map here. But we don't really need to, because the map here is just for iterating through the list xs. We can then use foldRight for this same purpose. So let's rewrite the map part using foldRight:
def flatMap[A, B](xs: List[A])(f: A => List[B]): List[B] = {
val tmp = xs.foldRight(List[List[B]]())((curr, acc) => f(curr) :: acc) // List[List[B]]
tmp.foldRight(List[B]())((outCurr, outAcc) => outCurr ++ outAcc)
}
OK, let's verify the new code:
scala> def flatMap[A, B](xs: List[A])(f: A => List[B]): List[B] = {
| val tmp = xs.foldRight(List[List[B]]())((curr, acc) => f(curr) :: acc) // List[List[B]]
| tmp.foldRight(List[B]())((outCurr, outAcc) => outCurr ++ outAcc)
| }
flatMap: [A, B](xs: List[A])(f: A => List[B])List[B]
scala> flatMap(List(1, 2, 3))(i => List(i, 2*i, 3*i))
res3: List[Int] = List(1, 2, 3, 2, 4, 6, 3, 6, 9)
OK, so far so good. So let's optimize the code a bit, which is instead of having two foldRight in sequential, we'll combine them into just one foldRight. That shouldn't be too hard:
def flatMap[A, B](xs: List[A])(f: A => List[B]): List[B] = {
xs.foldRight(List[B]()) { (curr, acc) => // Note: acc is List[B]
val tmp2 = f(curr) // List[B]
tmp2 ++ acc
}
}
Verify again:
scala> def flatMap[A, B](xs: List[A])(f: A => List[B]): List[B] = {
| xs.foldRight(List[B]()) { (curr, acc) => // Note: acc is List[B]
| val tmp2 = f(curr) // List[B]
| tmp2 ++ acc
| }
| }
flatMap: [A, B](xs: List[A])(f: A => List[B])List[B]
scala> flatMap(List(1, 2, 3))(i => List(i, 2*i, 3*i))
res4: List[Int] = List(1, 2, 3, 2, 4, 6, 3, 6, 9)
OK, so let's look at our constraints, it looks like we can't use ++ operation. Well, ++ is just a way to append the two List[B] together, so we can certainly achieve the same thing using foldRight method, like this:
def flatMap[A, B](xs: List[A])(f: A => List[B]): List[B] = {
xs.foldRight(List[B]()) { (curr, acc) => // Note: acc is List[B]
val tmp2 = f(curr) // List[B]
tmp2.foldRight(acc)((inCurr, inAcc) => inCurr :: inAcc)
}
}
And then, we can combine them all into one line by:
def flatMap[A, B](xs: List[A])(f: A => List[B]): List[B] =
xs.foldRight(List[B]())((curr, acc) =>
f(curr).foldRight(acc)((inCurr, inAcc) => inCurr :: inAcc))
Isn't it the given answer :)
Sometimes it is easier to understand with a simple example:
Suppose we have a val xs = List[Int](1,2,3) and a function f: Int => List[Int], f(x) = List(x,x) (lambda x => List(x,x))
Appling f to each element of xs List(f(1),f(2), f(3)) will result in List(List(1,1),List(2,2),List(3,3)) so we need to flatten out this List[List[Int]]. The final result should be List(1, 1, 2, 2, 3, 3). Given Cons (::) the constructor of nonempty List, this should be Cons(1, Cons(1, Cons(2, Cons(2, Cons(3, Cons(3, Nil)))))). Observe foldRight operation in the result, which applies the constructor Cons (::) to the result of f applied to each element of the list xs. So a first implementation of flatMap would be
def flatMap[A,B](xs: List[A])(f: A => List[B]): List[B] = xs match {
case Cons(head, tail) => foldRight(f(head), Nil)((a,b) => Cons(a,b))
}
In this form, flatMap(List(1,2,3)) will return List(1,1) or Cons(1,1,Nil) (by substitution). So we need to continue down with a recursive call to flatMap on the tail (reducing the problem by 1 from 3(elements) to 2(elements)) and adding the base case for the case of an empty List as Nil (Nil is the "zero" element for Cons operation)
def flatMap[A,B](xs: List[A])(f: A => List[B]): List[B] = xs match {
case Nil => Nil
case Cons(head, tail) => foldRight(f(head), flatMap(tail)(f))((a,b) => Cons(a,b))
}
which is the final implementation.
I'm having a look at the following code
http://aperiodic.net/phil/scala/s-99/p26.scala
Specifically
def flatMapSublists[A,B](ls: List[A])(f: (List[A]) => List[B]): List[B] =
ls match {
case Nil => Nil
case sublist#(_ :: tail) => f(sublist) ::: flatMapSublists(tail)(f)
}
I'm getting a StackOverflowError for large values presumably because the function is not tail recursive. Is there a way to transform the function to accommodate large numbers?
It is definitely not tail recursive. The f(sublist) ::: is modifying the results of the recursive call, making it a plain-old-stack-blowing recursion instead of a tail recursion.
One way to ensure that your functions are tail recursive is to put the #annotation.tailrec on any function that you expect to be tail recursive. The compiler will report an error if it fails to perform the tail call optimization.
For this, I would add a small helper function that's actually tail recursive:
def flatMapSublistsTR[A,B](ls: List[A])(f: (List[A]) => List[B]): List[B] = {
#annotation.tailrec
def helper(r: List[B], ls: List[A]): List[B] = {
ls match {
case Nil => r
case sublist#(_ :: tail) => helper(r ::: f(sublist), tail)
}
}
helper(Nil, ls)
}
For reasons not immediately obvious to me, the results come out in a different order than the original function. But, it looks like it works :-) Fixed.
Here is another way to implement the function:
scala> def flatMapSublists[A,B](ls: List[A])(f: (List[A]) => List[B]): List[B] =
| List.iterate(ls, ls.size)(_.tail).flatMap(f)
flatMapSublists: [A, B](ls: List[A])(f: List[A] => List[B])List[B]
A simply comparison between dave's flatMapSublistsTR and mine:
scala> def time(count: Int)(call : => Unit):Long = {
| val start = System.currentTimeMillis
| var cnt = count
| while(cnt > 0) {
| cnt -= 1
| call
| }
| System.currentTimeMillis - start
| }
time: (count: Int)(call: => Unit)Long
scala> val xs = List.range(0,100)
scala> val fn = identity[List[Int]] _
fn: List[Int] => List[Int] = <function1>
scala> time(10000){ flatMapSublists(xs)(fn) }
res1: Long = 5732
scala> time(10000){ flatMapSublistsTR(xs)(fn) }
res2: Long = 347232
Where the method flatMapSublistsTR is implemented as:
def flatMapSublistsTR[A,B](ls: List[A])(f: (List[A]) => List[B]): List[B] = {
#annotation.tailrec
def helper(r: List[B], ls: List[A]): List[B] = {
ls match {
case Nil => r
case sublist#(_ :: tail) => helper(r ::: f(sublist), tail)
}
}
helper(Nil, ls)
}
def flatMapSublists2[A,B](ls: List[A], result: List[B] = Nil)(f: (List[A]) => List[B]): List[B] =
ls match {
case Nil => result
case sublist#(_ :: tail) => flatMapSublists2(tail, result ++ f(sublist))(f)
}
You generally just need to add a result result parameter to carry from one iteration to the next, and spit out the result at the end instead of adding the end to the list.
Also that confusting sublist# thing can be simplified to
case _ :: tail => flatMapSublists2(tail, result ++ f(ls))(f)
Off-topic: here's how I solved problem 26, without the need for helper methods like the one above. If you can make this tail-recursive, have a gold star.
def combinations[A](n: Int, lst: List[A]): List[List[A]] = n match {
case 1 => lst.map(List(_))
case _ => lst.flatMap(i => combinations (n - 1, lst.dropWhile(_ != i).tail) map (i :: _))
}