Why scala can't pass a function name directly to a val? - scala

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

Related

Execute functions in a List

I have Object in scala in which I have defined some functions.
Object Sample {
val listFunction = Seq(func1(a,b),func2(p,q))
def func1(a: Int,b : Int) : Int ={
val c = a+b
c
}
def func2(p: Int,q : Int) : Int ={
val d = p+q
}
}
def main(args: Array[String]): Unit = {
//Want to call the list and execute the functions
ListFunction
}
How to call the list in main method and execute it?
Given
def func1(a: Int, b: Int): Int = a + b
def func2(p: Int, q: Int): Int = p + q
Consider the difference between
val x: Int = func1(2, 3) // applied function
val f: (Int, Int) => Int = func1 // function as value
So you have to use functions as values as you pass them to the sequence like so
val listFunction: Seq[(Int, Int) => Int] = Seq(func1, func2)
and then map over the list to apply the functions
listFunction.map(f => f.apply(2, 3))
listFunction.map(f => f(2, 3))
listFunction.map(_(2, 3))
scastie

why currying does not work with a function literal?

What is the logical reason that the first form works and not the second?
scala> val d = (a: Int, b: Int) => a + b
d: (Int, Int) => Int = <function2>
scala> val d = (a: Int)(b: Int) => a + b
<console>:1: error: not a legal formal parameter.
Note: Tuples cannot be directly destructured in method or function parameters.
Either create a single parameter accepting the Tuple1,
or consider a pattern matching anonymous function: `{ case (param1, param1) => ... }
val d=(a:Int)(b:Int)=>a+b
Because multiple parameter lists aren't allowed on function declarations. If you want to curry a function, you do:
scala> val d: Int => Int => Int = a => b => a + b
d: Int => (Int => Int) = $$Lambda$1106/512934838#6ef4cbe1
scala> val f = d(3)
f: Int => Int = $$Lambda$1109/1933965693#7e2c6702
scala> f(4)
res6: Int = 7
You can also create a single parameter list and partially apply it:
scala> val d = (a: Int, b: Int) => a + b
d: (Int, Int) => Int = $$Lambda$1064/586164630#7c8874ef
scala> d(4, _: Int)
res2: Int => Int = $$Lambda$1079/2135563436#4a1a412e
We partially applied d with 4, and we got back a function, Int => Int, which means when we supply the next argument, we'll get the result:
scala> res2(3)
res3: Int = 7
We can also create a named method, and use eta-expansion to create a curried function out of it:
scala> def add(i: Int)(j: Int): Int = i + j
add: (i: Int)(j: Int)Int
scala> val curriedAdd = add _
curriedAdd: Int => (Int => Int) = $$Lambda$1115/287609100#f849027
scala> val onlyOneArgumentLeft = curriedAdd(1)
onlyOneArgumentLeft: Int => Int = $$Lambda$1116/1700143613#77e9dca8
scala> onlyOneArgumentLeft(2)
res8: Int = 3
Function currying is possible.
val curryFunc = (a: Int) => (b: Int) => a + b
curryFunc now has the type Int => (Int => Int)

How to make scala shell to show an anonymous function?

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>

Why does this partial application not compile?

The following:
val add = (a: Int, b: Int) => a + b
gets converted to:
object add extends Function2[Int, Int, Int] {
def apply(a: Int, b: Int) = a + b
}
while
val a1 = add(_: Int, 3)
gets converted to:
object a1 extends Function1[Int, Int] {
def apply(x: Int): Int = {
add(x, 3)
}
}
But when I do:
scala> val a2 = add _
a2: () => (Int, Int) => Int = <function0>
And then call a2, it throws an error:
scala> a2(1, 2)
<console>:11: error: too many arguments for method apply: ()(Int, Int) => Int in trait Function0
a2(1, 2)
^
Why is this? Why does the following work?
a2()(1, 2)
add is already a Function2[Int, Int, Int]. If you want a2 to have the same type, then a simple assignment will suffice.
scala> val a2 = add
a2: (Int, Int) => Int = <function2>
scala> a2(1, 2)
res3: Int = 3
What you're thinking of is eta-expansion of a method into a function. If we had:
def add(a: Int, b: Int): Int = a + b
Then, we would use add _ to get the eta-expansion to assign to a value.
scala> def a2 = add _
a2: (Int, Int) => Int
scala> a2(1, 2)
res4: Int = 3
But add is already a function, so the underscore has a different meaning. add is now a value and not a method. Since add is a value, it is like a parameter-less method that returns a Function2[Int, Int, Int]. And if we try to get the eta-expansion of that, we get () => Function2[Int, Int, Int].
Consider a simpler example where we have a simple val a = 1. a is essentially the same as a parameter-less method that returns 1 (def a = 1). If I try to obtain the eta-expansion, I will get () => Int.
scala> val a = 1
a: Int = 1
scala> val a2 = a _
a2: () => Int = <function0>

How to compose to methods, without duplicate input arguments

Suppose I have two methods
scala> def a(a: Int, b: Int, c: Int) : Int = …
a: (a: Int, b: Int, c: Int)Int
scala> def b(i: Int) : Int = …
b: (i: Int)Int
How to define a method c, that is the composition of both ?
Unfortunately, the following code doen't compile :
def c = b(a)
You could convert method a to function and then use method andThen like this:
def a(a: Int, b: Int, c: Int) : Int = a + b + c
def b(i: Int) : Int = i * 2
val c = (a _).tupled andThen b
c(1, 1, 1)
// 6
Note that I have to convert function (Int, Int, Int) => Int to tupled version - ((Int, Int, Int)) => Int - here to use andThen. So result function c accepts Tuple3 as argument.
You could convert c to untupled version ((Int, Int, Int) => Int) using Function.untupled:
val untupledC = Function.untupled(c)
untupledC(1, 1, 1)
// 6
shapeless
There is no untupled method for function arity > 5.
You could also use shapeless toProduct/fromProduct methods for any arity like this:
import shapeless.ops.function._
import shapeless.ops.function._
val c = (a _).toProduct.andThen(b).fromProduct
Scalaz defines Functor instances for higher-arity functions, so you can just write
(a _).map(b)