I came from Java and would like to combine two partial functions like this:
def sum(a: Int, b: Int, c: Int) : Int = a + b + c
I want write something like this:
val l = List(1, 2, 3)
l.foreach(println _ sum (1, _ : Int, 3) ) // It's supposed to apply
// the partial sum(1, _: Int, 3)
// and println computed value.
But it refuses to compile. Is there a way to fix it concisely?
There are few problems with what you were trying to do. First of all, println is an overloaded method, so when you are trying to eta-expand it to a function like this println _, Scala is taking the shortest form, which is the one with 0 arguments:
scala> println _
res0: () => Unit = $$Lambda$1048/48841776#58ec44ec
So you need to be more specific:
scala> println(_: Int)
res1: Int => Unit = $$Lambda$1064/1621799037#1e8bddc4
Now that we have correct function there is one more thing to do: to add compose and proper parentheses (additional parentheses wrap anonymous functions):
scala> l.foreach((println(_: Int)) compose (sum (1, _: Int, 3)))
5
6
7
or in the other direction:
scala> l.foreach((sum (1, _: Int, 3)) andThen (println(_: Int)))
5
6
7
Assuming I reading what you want correctly (and even the code it's a huge assumption), here a snippet that might achieve it:
scala> def sum(a: Int, b: Int, c: Int) : Int = a + b + c
sum: (a: Int, b: Int, c: Int)Int
scala> val sum13 = sum(1, _ : Int, 3)
sum13: Int => Int = <function1>
scala> val printInt = println( _ : Int )
printInt: Int => Unit = <function1>
scala> List(1,2,4) foreach { printInt compose sum13 }
5
6
8
Notice the compose. Another way would be explicitly compose x => printInt(sum13(x)).
Related
I have this scala code:
object C extends App{
def sum(a:Int,b:Int,c:Int)=a+b+c
//val d=sum
val d=sum _
println(d(1,2,3))
}
I have to write sum _,not sum
but In f#,I can write this:
let sum a b c=a+b+c
let d=sum
[<EntryPoint>]
let main argv =
printfn "%A" (d 1 2 3)
0 // return an integer exit code
why in scala I can't just write
val d=sum
Scala has
methods (by default def is a method) and
functions
And they are not same.
Taking java methods as example, you can not assign methods to a variable without evaluating the method. But you can do that with function and to achieve that in scala define sum as function.
scala> def sum: (Int, Int, Int) => Int = (a, b, c) => a + b + c
sum: (Int, Int, Int) => Int
scala> val sumVal = sum
sumVal: (Int, Int, Int) => Int = $$Lambda$912/0x0000000801667840#716f94c1
scala> sumVal(1, 2, 3)
res1: Int = 6
Longer version of defining a function is,
scala> def sum = new Function3[Int, Int, Int, Int] {
| def apply(a: Int, b: Int, c: Int): Int = a +b + c
| }
sum: (Int, Int, Int) => Int
scala> val sumVal = sum
sumVal: (Int, Int, Int) => Int = <function3>
scala> sumVal(1, 2, 3)
res2: Int = 6
I am having trouble understanding why I am unable to use a composed function and compose a new one. For eg: I have two functions f and g and I create a composed function composed1 from these. I tried to combine composed with fourth function lastOne and it fails.
I want to make two composed functions and for the second one Is there a way I can reuse the first composed function?
scala> def f(x: Int)(y: Int) = {
| x + y
| }
f: (x: Int)(y: Int)Int
scala> def g(a: Int)(b: Int) = {
| a + b
| }
g: (a: Int)(b: Int)Int
scala> def composed1(a: Int, b: Int) = {
| f(a) _ andThen g(b)
| }
composed1: (a: Int, b: Int)Int => Int
scala> composed1(2, 2)(5)
res1: Int = 9
scala> def lastOne(l: Int)(x: Int) = {
| l + x
| }
lastOne: (l: Int)(x: Int)Int
scala> def composed2(a: Int, b: Int, c: Int) = {
| composed1(a, b) _ andThen lastOne(c)
| }
<console>:14: error: _ must follow method; cannot follow Int => Int
composed1(a, b) _ andThen lastOne(c)
^
<console>:14: error: missing argument list for method lastOne
Unapplied methods are only converted to functions when a function type is expected.
You can make this conversion explicit by writing `lastOne _` or `lastOne(_)(_)` instead of `lastOne`.
composed1(a, b) _ andThen lastOne(c)
When I use all of them together it works
scala> def test(x: Int, y: Int, z: Int) = {
| f(x) _ andThen g(y) _ andThen lastOne(z)
| }
test: (x: Int, y: Int, z: Int)Int => Int
scala> test(2, 2, 4)(5)
res9: Int = 13
f()() and g()(), as you define them, are methods. Methods are not functions but methods can be promoted to functions via "eta expansion". One way to do that is using the underscore in place of a passed parameter.
andThen() is a method on the Function trait that takes a function as an argument and returns a new function. It looks as if you can also use a method as the passed argument but it is silently being promoted to Function status.
So composed1() looks like a method but it is actually a Function, because that's what andThen() returns, and you can't apply the underscore eta expansion to a Function. It only works on methods.
As an experiment, turn f()() into a Function that does the same thing...
def f :Int => Int => Int = (x: Int) => (y: Int) => x + y
...now composed1() won't compile.
So, now that we know that composed1() is a Function, how do we get what we want from composed2()? Simple. Skip the underscore.
def composed2(a: Int, b: Int, c: Int) =
composed1(a, b) andThen lastOne(c)
composed2(2, 2, 4)(5) //res0: Int = 13
After experimenting with scala's eta expansion, I came across a weird feature.
Let's define a method:
scala> def sum(a: Int, b: Int): Int = a + b
sum: (a: Int, b: Int)Int
Ok, up until now, everything is fine. Now let's assign it to a val using eta expansion:
scala> val f = sum _
f: (Int, Int) => Int = $$Lambda$1051/694580932#55638165
Now, the strange thing is coming. I can apply eta expansion again to f, and it is working (however it adds currying to my method) :
scala> val g = f _
g: () => (Int, Int) => Int = $$Lambda$1055/1351568309#5602e540
Why is this working ? I thought that eta expansion was only valid for methods.
Moreover, I noticed that this is not possible:
scala> ((a: Int, b: Int) => a + b: Int) _
<console>:12: error: _ must follow method; cannot follow (Int, Int) => Int
((a: Int, b: Int) => a + b: Int) _
^
But is it not the same as applying eta expansion to f ?
I am a bit confused and these eta expansions still hide some magic for me.
Thanks a lot !
When you write val f = sum _ at the top level of the REPL or an object/class, Scala defines an accessor method so that you can access it. Here is how Scala desugars this (via scalac -Xprint:typer on val f: (Int, Int) => Int = _ + _):
private[this] val f: (Int, Int) => Int = ((x$1: Int, x$2: Int) => x$1.+(x$2));
<stable> <accessor> def f: (Int, Int) => Int = Foo.this.f;
So, when you subsequently write val g = f _, it's doing eta-expansion on the zero-argument accessor method, which results in the behavior you see. For more verification of this, notice that, if you put the definitions in a method, you get an error:
def foo = {
val f: (Int, Int) => Int = _ + _
val g = f _ // error: _ must follow method; cannot follow (Int, Int) => Int
}
This is because accessors are only generated for fields (and top-level REPL definitions, which are treated like fields).
I am learning scala and a typical example is the definition of an anonymous function:
scala> (x: Int) => x + 7
res11: Int => Int = <function1>
How do I make the shell to show me the body of <function1>?
Which would be x + 7 in the above case.
This becomes interesting if a function is partially applied:
scala> def adder(m: Int, n: Int) : Int = m + n
adder: (m: Int, n: Int)Int
scala> val add2 = adder(2, _:Int)
add2: Int => Int = <function1>
I'm fairly new to Scala and functional programming in general so I'm having a bit trouble wrapping my head around the concept of partially applied functions and function currying. There's also a pretty high chance that I'm gonna mix up some terminology, so all corrections are appreciated.
Note: I'm using the Scala Play framework but this is more of a Scala problem than a Play problem.
Given a function like this
def create(id: Long, userId: Long, label: String)
I get the userId and label as a (Int, String) tuple and the id as a Long. Basically what I'm trying to do is passing the id and the tuple to the function at the same time.
Now, I've read that passing a tuple to a function can be done something like this
scala> def f(a: Int, b: String) = 0
f: (a: Int, b: String)Int
scala> (f _).tupled((2, "Hello"))
res0: Int = 0
and that it is also possible to partially apply a function like this
scala> def f(a: Int, b: String) = 0
f: (a: Int, b: String)Int
scala> val ff = f(_: Int, "Hello")
ff: Int => Int = <function1>
scala> ff(2)
res1: Int = 0
So my initial idea was to combine these two concepts something like this
scala> def g(a: Long, b: Int, c: String) = 0
g: (a: Long, b: Int, c: String)Int
scala> val h = g(1, _: Int, _: String)
h: (Int, String) => Int = <function2>
scala> (h _).tupled((2, "Hello"))
However this results in an error
<console>:10: error: _ must follow method; cannot follow h.type
(h _).tupled((1, "Hello"))
^
So my question is first of all why doesn't this work because to me this makes sense. And secondly how would I go about achieving this effect?
Thanks for your help!
Just don't abstract it twice: don't do redundand underscore to the h as it's already a function after partial-applying:
scala> def create(a: Long, b: Int, c: String) = 0
create: (a: Long, b: Int, c: String)Int
scala> val h = create(1, _: Int, _: String)
h: (Int, String) => Int = <function2>
scala> h.tupled((1, "Hello"))
res0: Int = 0
More deeply, tupled is defined on functions (means object of Function, like Int => String), not on methods (like def f(i: Int): String) - so sometimes you need to convert a method to the function - it's called eta-expansion (or eta-abstraction more generally). When you do partial applying - eta-expansion is done automatically (you already have a (Int, String) => Int) - so you don't have to do it twice.
See The differences between underscore usage in these scala's methods, Difference between method and function in Scala for more information.