def curry[A,B,C](f: (A, B) => C): A => (B => C) =
(a: A) => f(a, _)
def curry[A,B,C](f: (A, B) => C): A => (B => C) =
(a: A) => (b: B) => f(a, b)
What I was thinking was that in the first implementation I would take the function f and pass in an A and an anything (but the compiler will type check that the second param is a B) to get a C out.
Yes, they are identical. If you compile:
object Test {
def curry[A,B,C](f: (A, B) => C): A => (B => C) =
(a: A) => f(a, _)
def curry2[A,B,C](f: (A, B) => C): A => (B => C) =
(a: A) => (b: B) => f(a, b)
}
with -Xprint:typer, you get the intermediate abstract syntax tree:
[[syntax trees at end of typer]]
package <empty> {
object Test extends scala.AnyRef {
def <init>(): Test.type = {
Test.super.<init>();
()
};
def curry[A, B, C](f: (A, B) => C): A => (B => C) = ((a: A) => ((x$1: B) => f.apply(a, x$1)));
def curry2[A, B, C](f: (A, B) => C): A => (B => C) = ((a: A) => ((b: B) => f.apply(a, b)))
}
}
During the "typer" stage, when the compiler assigns types to everything, it realizes that the _ (now named x$1) must be type B.
Related
I started to learn the basics of scala and and I have problem with understanding simple function. I have three tasks to do. First of them was easy for me and i know how it works. But next two I don't understand what I have to write to return.
def compose[A,B,C](f: A => B)(g: B => C): A => C = {
a: A => g(f(a))
}
def prod[A,B,C,D](f: A => C, g: B => D): (A, B) => (C, D) {
???????????
}
def lift[A,T](op: (T,T) => T)(f: A => T, g: A => T): A => T {
??????????
}
Let's look at the types, you should be able to implement the method quite easily by looking at the them.
Start with prod, start by writing the input parameters and expected output:
def prod[A,B,C,D](f: A => C, g: B => D): (A, B) => (C, D) = {
(a: A, b: B) => {
val c: C = ???
val d: D = ???
(c, d)
}
}
Then, how can you build c and d given what you have (that is f and g)?
I let you answer this question by yourself.
The same can be applied for lift:
def lift[A,T](op: (T,T) => T)(f: A => T, g: A => T): A => T {
(a: A) => {
val t: T = ???
}
}
This one might be a bit trickier if you have no idea what lift is supposed to do though.
Hint: you probably have to use f and g, otherwise they wouldn't exist. Then from the values you get, how to get the desired output type?
I've got an exercise to create a product of two functions from the code below:
def prod[A, B, C, D](f: A => C, g: B => D): (A, B) => (C, D) = {
}
My plan was to do something like this, but it doesn't work, because it can't resolve symbols A and B.
def prod[A, B, C, D](f: A => C, g: B => D): (A, B) => (C, D) = {
v1: (A,B) => f(A)*g(B)
}
The syntax to define a function type signature and a function definition is different. When you return a value, you need to return the function definition.
def prod[A, B, C, D](f: A => C, g: B => D): (A, B) => (C, D) =
(a: A, b: B) => (f(a), g(b))
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.
I'm implementing the List type in Scala when following a book.
Here's the definition of my List type:
sealed trait List[+A]
case object Nil extends List[Nothing]
case class Cons[+A](head: A, tail: List[A]) extends List[A]
All the later mentioned functions are defined in the companion object List in the same file
object List
I wrote foldLeft and foldRight as the following
def foldLeft[A,B](l: List[A], z: B)(f: (B, A) => B): B = l match {
case Nil => z
case Cons(x, xs) => foldLeft(xs, f(z, x))(f)
}
def foldRight[A,B](l: List[A], z: B)(f: (A, B) => B): B = l match {
case Nil => z
case Cons(x, xs) => f(x, foldRight(xs, z)(f))
}
There's an exercise on the book, which is to implement foldLeft using foldRight. Here's my initial implementation
def foldLeftWithRight[A,B](l: List[A], z: B)(f: (B, A) => B): B = {
foldRight(l, z)((a: A, b: B) => f(b, a))
}
Then I think I should write another function to do the reverse arguments if I'm to implement foldRight using foldLeft. As follows:
def reverseArgs[A,B](f: (A, B) => B): (B, A) => B = {
(b: B, a: A) => f(a, b)
}
So I changed code of foldLeftWithRight to the following:
def foldLeftWithRight[A,B](l: List[A], z: B)(f: (B, A) => B): B = {
foldRight(l, z)(reverseArgs(f))
}
And IntelliJ is complaining about reverseArgs(f):
Type mismatch: expected (A, B) => B, actual (B, B) => B
When I try to compile the code, the error is the following:
Error:(21, 37) type mismatch;
found : (B, A) => B
required: (B, Any) => Any
foldRight(l, z)(reverseArgs(f))
An interesting observation is that when I use the reverseArgs on foldRightWithLeft, there's no problem at all:
def foldRightWithLeft[A,B](l: List[A], z: B)(f: (A, B) => B): B = {
foldLeft(l, z)(reverseArgs(f))
}
What is going on here?
If you rename type parameters of your reverseArgs function to X and Y, you'll get something like
def reverseArgs[X ,Y](f: (X, Y) => Y): (Y, X) => Y = ???
Type of f in foldLeftWithRight is (B, A) => B. Passing that to reverseArgs means that:
X = B
Y = A
Y = B
I guess Intellij infers from here that A = B and this is why it's complaining that (B, B) => B isn't (A, B) => B. Scalac decides that Y = Any instead, because it's the least upper bound of two potentially unrelated types.
Good solution here is to generalize more. Return type of reversed function does not have to be one of parameter types, so you can introduce another generic type for that:
def reverseArgs[X ,Y, Z](f: (X, Y) => Z): (Y, X) => Z = {
(b: Y, a: X) => f(a, b)
}
see https://www.fpcomplete.com/user/edwardk/phoas
some background code
trait ProfunctorStr[->[_, _]] {
def dimap[A, B, C, D]: (C => A) => (B => D) => (A -> B) => (C -> D) = { f =>
g => {
lazy val h: (A -> B) => (C -> B) = mapfst(f)
lazy val hh: (C -> B) => (C -> D) = mapsnd(g)
h andThen hh
}
}
def mapfst[A, B, C]: (C => A) => (A -> B) => (C -> B) =
f => p => dimap[A, B, C, B](f)(x => x)(p)
def mapsnd[A, B, C]: (B => C) => (A -> B) => (A -> C) =
f => p => dimap[A, B, A, C](x => x)(f)(p)
// convenient for certain implementations
def mfst[A, B, C](p: A -> B)(f: C => A): C -> B = mapfst(f)(p)
def msnd[A, B, C](p: A -> B)(f: B => C): (A -> C) = mapsnd(f)(p)
}
abstract class Rec[F[_, _], A, B] {
def runRec[R]: (B => R) => (F[A, R] => R) => R
}
object Rec {
abstract class RecProfunctor[F[_, _]](implicit F: ProfunctorStr[F])
extends ProfunctorStr[({type l[x, y] = Rec[F, x, y] })#l] {
def dimap[A, B, C, D] = { f =>
g => rab =>
def P = function1Profunctor
new Rec[F, C, D] {
def runRec[R] = { ??? }
}
}
}
}
reading that article I feel like I get the gist but I'm having trouble implementing in scala, particularly how to transform that Rec[F, C, D] { runRec[R] = { ?!?!?! } } I really want to get this so if you can explain how to transform that
(B => R) => (F[A, R] => R) => R
into
(D => R) => (F[C, R] => R) => R
I think...
Any way any and all help is very much appreciated, and detail as deeply loved. thank you