How to bind second parameter in scala curry function? - scala

//a curry function
def find(a: Seq[Int])(sort: (Int, Int) => Boolean)
//My attempt
val findWithBiggerSort = find(_)((a,b) => a > b)
The findWithBiggerSort can't work, a compiler error occurred:
scala> def find(a: Seq[Int])(sort: (Int, Int) => Boolean)
| ={}
find: (a: Seq[Int])(sort: (Int, Int) => Boolean)Unit
scala> val findWithBiggerSort = find(_)((a,b) => a > b)
<console>:11: error: missing parameter type for expanded function ((x$1) => find(x$1)(((a, b) => a.$greater(b))))
val findWithBiggerSort = find(_)((a,b) => a > b)
^
how can I bind the second curry parameter?
how about bind second parameter as this
def find(a: Seq[Int], b: String)(sort: (Int, Int) => Boolean)

You have two issues:
The type of your sort function is wrong - you need a (Int, Int) => Boolean but you provide an (Int, Int) => Int. If you change it to:
val findWithBiggerSort = find(_)((a,b) => (a > b))
you get an error for a missing type of the _ parameter provided in find (_). If you provide this type it compiles i.e.
val findWithBiggerSort = find(_:Seq[Int])((a,b) => (a > b))
or
val findWithBiggerSort = find(_:Seq[Int])(_ > _)

Related

Scala function typing issue

I'm given a list lis of type List[(Char,Int)] and need to sort it by chars, but I want do do this using sortWith function. One way to do this is using:
val newlis = lis.sortWith({case ((a,b),(c,d)) => a<c })
But when I wrote auxilary function:
def aux2(term: ((Char, Int),(Char, Int)) ): Boolean = term match {
case ((a,b),(c,d)) => a<c
case _ => false
}
lis.sortWith(aux2)
I get type mismatch. Why is that?
There is a difference between
def f(a: A, b: B): C
and
def f(ab: (A, B)): C
When lifted and desugared, the first one becomes a Function2[A, B, C], while the second one becomes Function[(A, B), C]. While essentially the same (isomorphic), these two types must be used with a slightly different syntax.
Here is a slightly more complex example with (Char, Int) instead of A and B:
def g1(abcd: ((Char, Int), (Char, Int))): Boolean = abcd._1._2 < abcd._2._2
val g1Fun: (((Char, Int), (Char, Int))) => Boolean = g1
// ^^^ ^
// || \ second component of tuple: (Char, Int)
// || first component of tuple: (Char, Int)
// | \
// | single argument of type ((Char, Int),(Char, Int))
// \
// argument list of `g1Fun`, accepts *one* argument
def g2(ab: (Char, Int), cd: (Char, Int)): Boolean = ab._2 < cd._2
val g2Fun: ((Char, Int), (Char, Int)) => Boolean = g2
// ^^ ^
// || second argument of type (Char, Int)
// | \
// | first argument of type (Char, Int)
// \
// argument list of `g2Fun`, needs *two* arguments
The function lt in sortWith behaves like the second function g2Fun, whereas the function aux2 that you have written is more like the g1Fun.
So, to fix your code, you have to define aux2 as a binary operation:
val lis: List[(Char,Int)] = List(('a', 34), ('b', 42))
println(lis.sortWith({case ((a,b),(c,d)) => a < c }))
def aux2(
firstTerm: (Char, Int),
secondTerm: (Char, Int)
): Boolean = (firstTerm, secondTerm) match {
case ((a,b), (c,d)) => a < c
case _ => false
}
println(lis.sortWith(aux2))
To make it work with the same arity of f as you have written, the sortWith would have to accept a slightly different sort of functions.
Consider this:
def watchTheArity(f: ((Int, Int)) => Int): Int = {
f((4, 5))
}
See the weird double parens wrapping the (Int, Int) part?
This means: "I expect an f that takes a single tuple as argument".
Therefore, this works:
def f(ab: (Int, Int)): Int = ab._1 + ab._2
println(watchTheArity(f))
However, if it were defined as
def watchTheArity2(f: (Int, Int) => Int): Int = {
f(4, 5)
}
then you would need an f that takes two arguments.
Edit notice Added Ascii-art explanation of parentheses.

Scala method that takes a function as a parameter and then executes it

I want to write a simple method that takes a function as a parameter and then executes it.
def exec(f: (a:Int, b:Int) => Boolean): Boolean = f(a,b)
I'm not sure what is wrong with the above, but I get the error:
<console>:1: error: ')' expected but ':' found.
def exec(f: (a:Int, b:Int) => Boolean): Boolean = f(a,b)
^ ^
| |
// These are supposed to be types, but a: Int and b: Int aren't types,
// they are identifiers with type ascriptions.
It should look a little more like:
def exec(f: (Int, Int) => Boolean): Boolean = f(a, b)
Now f is a function (Int, Int) => Boolean. But this doesn't compile, because a and b are not defined.
You either need to pass them in, or fix them to a value.
def exec(a: Int, b: Int)(f: (Int, Int) => Boolean): Boolean = f(a, b)
scala> exec(2, 3)(_ > _)
res1: Boolean = false
If you want to execute a function with parameters in your exec method you need to:
scala> def exec(f: => Unit) = {
| println("Exec:")
| f
| }
scala> def foo(f : (Int, Int)): Unit = println(f._1 + f._2)
scala> exec(foo((3, 4)))
Exec:
7
because foo((3, 4)) type is => Unit
Not quite an answer to your original question (and too big to be a comment), but if you're looking to write a tasteful, nice-looking execution operator and don't particularly like the syntax of the provided answers, perhaps something similar to scalaz's pipe operator (|>) might be what you're thinking of?
scala> // You could just get this from scalaz with import scalaz._ and import Scalaz._
scala> implicit class FancyExec[A](x: A){def |>[B](f: A => B) = f(x)}
scala> 5 |> (_ + 6)
res1: Int = 11
scala> (5, 4) |> ((_: Int) < (_: Int)).tupled
res2: Boolean = false
scala> val f = ((_: Int) < (_: Int)).tupled
f: ((Int, Int)) => Boolean = <function1>
scala> val g = ((_: Int) > (_: Int)).tupled
g: ((Int, Int)) => Boolean = <function1>
scala> List(f, g) map ((5, 4) |> _)
res3: List[Boolean] = List(false, true)

scala : it is impossible to put a tuple as a function's argument

I can't pass a tuple as a method parameter:
scala> val c:Stream[(Int,Int,Int)]= Stream.iterate((1, 0, 1))((a:Int,b:Int,c:Int) => (b,c,a+b))
<console>:11: error: type mismatch;
found : (Int, Int, Int) => (Int, Int, Int)
required: ((Int, Int, Int)) => (Int, Int, Int)
thanks.
Just as the function literal:
(x:Int) => x + 1
is a function of one argument, the following
(x:Int, y: Int, z: Int) => x + y + z
is a function of three arguments, not one argument of a 3tuple
You can make this work neatly using a case statement:
scala> val c: Stream[(Int,Int,Int)] =
Stream.iterate((1, 0, 1)){ case (a, b, c) => (b, c, a+b) }
c: Stream[(Int, Int, Int)] = Stream((1,0,1), ?)
An alternative is to pass the tuple, but that's really ugly due to all the _1 accessors:
scala> val c:Stream[(Int,Int,Int)] =
Stream.iterate((1, 0, 1))( t => (t._2, t._3, t._1 + t._2) )
c: Stream[(Int, Int, Int)] = Stream((1,0,1), ?)
The lambda (a:Int,b:Int,c:Int) => (b,c,a+b) is a function taking three arguments. You want it to take one tuple, so you can write ((a:Int,b:Int,c:Int)) => (b,c,a+b). But this gives an error!
error: not a legal formal parameter.
Note: Tuples cannot be directly destructured in method or function parameters.
Either create a single parameter accepting the Tuple3,
or consider a pattern matching anonymous function: `{ case (param1, ..., param3) => ... }
(((a:Int,b:Int,c:Int)) => (b,c,a+b))
^
Luckily, the error suggests a solution: { case (a, b, c) => (b, c, a+b) }
It is also possible to use the tupled option:
def a = (x:Int, y: Int, z: Int) => x + y + z).tupled
val sum = a((1,2,3))
My guess is that the expression (a:Int,b:Int,c:Int) => (b,c,a+b) defines a lambda with three arguments, and you need one decomposed argument.

Currying function from an existing answer is invalid

I tried running the below code:
val f: (a: Int) => (b: Int) => (c: Int) = a + b + c
found in this thread in the REPL and IntellijIDEA but it's apparently invalid.
From the REPL:
scala> val f: (a: Int) => (b: Int) => (c: Int) = a + b + c
<console>:1: error: ')' expected but ':' found.
val f: (a: Int) => (b: Int) => (c: Int) = a + b + c
^
Anyone knows why? My scala version is 2.10.1
Thank you
You write the type as if you were writing:
val a: 5 = 5
What you want is more like
val f = (a: Int) => (b: Int) => (c: Int) => a+b+c
To elaborate further the REPL will write
f: Int => (Int => (Int => Int)) = <function1>
Because function definition is right associative you could the type of f explicitly as follows
f: Int => Int => Int => Int = (a: Int) => (b: Int) => (c: Int) => a+b+c
If you explicitly give the function type like this the compiler does not need information about what a,b, and c are and you could simply write a => b => c => a+b+c instead.

How does a "case" anonymous function really work in Scala?

Dеar Scala,
scala> val f1: ((Int, Int)) => Int = { case (a, b) => a + b }
f1: ((Int, Int)) => Int = <function1>
scala> val f2: (Int, Int) => Int = { case (a, b) => a + b }
f2: (Int, Int) => Int = <function2>
huh?!
scala> f1(1, 2)
res2: Int = 3
Ok...
scala> def takesIntInt2Int(fun: (Int, Int) => Int) = fun(100, 200)
takesIntInt2Int: (fun: (Int, Int) => Int)Int
scala> def takesTuple2Int(fun: ((Int, Int)) => Int) = fun(100, 200)
takesTuple2Int: (fun: ((Int, Int)) => Int)Int
scala> takesIntInt2Int(f2)
res4: Int = 300
scala> takesIntInt2Int(f1)
<console>:10: error: type mismatch;
found : ((Int, Int)) => Int
required: (Int, Int) => Int
takesIntInt2Int(f1)
^
scala> takesTuple2Int(f1)
res6: Int = 300
scala> takesTuple2Int(f2)
<console>:10: error: type mismatch;
found : (Int, Int) => Int
required: ((Int, Int)) => Int
takesTuple2Int(f2)
Right. And now, look at this!
scala> takesTuple2Int { case (a, b, c) => a + b + c }
<console>:9: error: constructor cannot be instantiated to expected type;
found : (T1, T2, T3)
required: (Int, Int)
takesTuple2Int { case (a, b, c) => a + b + c }
^
scala> takesIntInt2Int { case (a, b, c) => a + b + c }
<console>:9: error: constructor cannot be instantiated to expected type;
found : (T1, T2, T3)
required: (Int, Int)
takesIntInt2Int { case (a, b, c) => a + b + c }
Like, srsly? o_O Both result in required: (Int, Int) error.
Why then use case at all in such anonymous functions?
See section 8.5 of the Scala reference (http://www.scala-lang.org/files/archive/nightly/pdfs/ScalaReference.pdf). The expression { case (a, b) => a + b } is interpreted differently based on the expected type. In your definition of f1 it created a PartialFunction[(Int, Int), Int] which was cast to a Function1[(Int, Int), Int], i.e. ((Int, Int)) => Int whereas in the definition of f2 it created a Function2[Int, Int, Int], i.e. (Int, Int) => Int.
These two interpretations relate to the two situations where you would commonly use case in an anonymous function.
One is for writing anonymous functions that accept tuples and work on their components, as you did with f1. An example would be the function you pass to the foreach or map method on a Map, e.g. Map(1 -> 2, 3 -> 4) map { case (k, v) => k + v }.
The second is for writing an anonymous function that does a match on its sole parameter. Your f2 is doing this, but not in any useful way. An example would be the anonymous function passed to collect, e.g. List(1, -2, 3) collect { case x if x > 0 => -x }.
Note that the two can be combined, that is functions like f1 can do complex matching as well. For example, Map(1 -> 2, 3 -> 4) collect { case (k, v) if k < 2 => v }.
Edit: res2 works because of tupling. If an application doesn't type check, the compiler will try wrapping the args in a tuple before failing.
But that is tried just for applications; it's not a general conversion, as you discovered. It will not try to upgrade a value Function2[A, B, C] to Function1[(A, B), C].