The syntax of currying in scala is for example
def f(x: Int, b: Int) = x + y
is
def f(x: Int)(b: Int) = x + y
And currying for sum to sum for given range a and b is
def sum(f: Int => Int, a: Int, b: Int) = {
...
}
sum(x=>x, 3, 6) // outcome is 18 (3+4+5+6)
is
def sum(f: Int => Int): (Int, Int) => Int = {
def sumF(a: Int, b: Int): Int =
if (a > b) 0
else f(a) + sumF(a + 1, b)
sumF
}
sum(x=>x)(3, 6) // outcome is 18 (3+4+5+6)
But I don't understand why colon(:)
exists between (f: Int => Int) and (Int, Int)
in def sum(f: Int => Int): (Int, Int) => Int = {
instead of
def sum(f: Int => Int)(Int, Int) => Int = {
Your sum example is not curried. If you wanted it curried you'd do something like:
def sum(f: Int => Int)(a: Int, b: Int): Int =
if (a > b) 0
else f(a) + sum(f)(a + 1, b)
sum(x=>x)(3, 6) // res0: Int = 18
Your code defines a method that takes a single argument, def sum(f: Int => Int). That argument is a function that takes and Int and returns an Int. So no currying involved.
This sum method returns a function, : (Int, Int) => Int. This returned function takes 2 Ints and returns and Int. Invoking this sum method looks like currying, but it's not.
sum(x=>x)(3, 6)
Instead you are invoking sum() with a single argument (x=>x) and then invoking the returned function with two arguments (3,6).
(Int, Int) => Int between : and = specify the function's return type, i.e, it says sum will return another method of signature (Int, Int) => Int which takes two Int and returns another Int, and this is the signature of your inner sumF function:
You can rewrite this to the currying syntax as follows:
def sum(f: Int => Int)(a: Int, b: Int): Int = {
def sumF(a: Int, b: Int): Int =
if (a > b) 0
else f(a) + sumF(a + 1, b)
sumF(a, b)
}
This will more or less do the same thing as the method defined in OP:
sum(x => x)(3, 6)
// res11: Int = 18
But these two definitions are not exactly the same, for instance, for the currying syntax defined here, if you want to generate a new method from it, you have to specify the variable type, like:
val mysum: (Int, Int)=> Int = sum(x => x)
But for the one in OP, it can be simply val mysum = sum(x => x) as the return type of sum as already been specified.
Related
def fact(n: Int) = products(x => x)(1,n)
fact(5)
def mapReduce(f: Int => Int, combine: (Int, Int) => Int, zero: Int)(a:Int,b:Int): Int =
def recur(a: Int): Int =
if(a>b) zero
else combine(f(a),recur(a+1))
recur(a)
def sum(f: Int => Int) = mapReduce(f, (x, y) => x+y, 0)
def products(f: Int => Int) = mapReduce(f, (x, y) => x*y, 1)
sum(fact)(1,5)
products(fact)(1,5)
def mapReduce(f: Int => Int, combine: (Int, Int) => Int, zero: Int)(a:Int,b:Int): Int = {
def recur(a: Int): Int =
if (a > b) zero
else combine(f(a), recur(a + 1))
recur(a)
}
def sum(f: Int => Int): (Int, Int) => Int = mapReduce(f, (x, y) => x+y, 0)
def products(f: Int => Int): (Int, Int) => Int = mapReduce(f, (x, y) => x*y, 1)
def fact(n: Int) = products(x => x)(1,n)
fact(5)
sum(fact)(1,5)
products(fact)(1,5)
I tried it using scala 2.13 on a scala worksheet, here curly brackets are needed for mapReduce as it contains two expressions one is a function definition and another a function invocation. Secondly when methods that returns functions such as sum and products the return type need to be specified. But I wasn't able to reproduce the error that you mentioned.
This is the Function.What are the arguments here?is it a function? and what is the return type?
def sum(f: Int => Int): (Int, Int) => Int = {
def sumf(a: Int, b: Int): Int = {...}
sumf
}
That is a function method called sum. It takes as parameter one function from Int to Int and returns a function that when called with a pair of Ints returns another Int.
The actual result depends on the implementation, but we could for instance define it as:
def sum(f: Int => Int): (Int, Int) => Int = {
def sumf(a: Int, b: Int): Int = {
f(a) + f(b)
}
sumf
}
Or simply:
def sum(f: Int => Int): (Int, Int) => Int = {
(a: Int, b: Int) => f(a) + f(b)
}
In that case, you could call it like this for instance:
def f(a: Int): Int = a * a
def g(a: Int, b: Int): Int = sum(f)(a, b)
val x: Int = g(3, 4) // x = 25
This question already has answers here:
Currying syntax in scala
(2 answers)
Closed 5 years ago.
In the course of funcional programming with Scala, I saw two form of declaration of a def. But I don't know the diferences between them, and the name given for this. How I can get more information about this?
Declaration 1
def sum(f: Int => Int)(a: Int, b: Int): Int = ???
Declaration 2
def sum(f: Int => Int, a: Int, b: Int): Int = ???
First one is called the curried syntax.
You can apply the function partially, then results in returning of a new function.
scala> def sum(f: Int => Int)(a: Int, b: Int): Int = f(a) + f(b)
sum: (f: Int => Int)(a: Int, b: Int)Int
scala> sum({x: Int => x + 1}) _
res10: (Int, Int) => Int = $$Lambda$1115/108209958#474821de
Second one is uncurried syntax but still we can apply the function partially even in this case.
scala> def sum(f: Int => Int, a: Int, b: Int): Int = f(a) + f(b)
sum: (f: Int => Int, a: Int, b: Int)Int
scala> sum({x: Int => x + 1}, _: Int, _: Int)
res11: (Int, Int) => Int = $$Lambda$1116/1038002783#1a500561
Again new function returned when applied partially.
There is no difference between above two declaration, Its just the syntactic sugar.
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)
I have a function named sum that can take a single parameter anonymous function as a parameter, and two Integers.
def sum (f: Int => Int , a: Int, b: Int): Int =
{
if(a > b) 0 else f(a) + sum(f, a + 1, b)
}
sum((x: Int) => x , 2, 10)
How could I modify the function definition so that it can take a multiple parameter function, so I could call it like this:
sum((y: Int, i: Int) => y + i => x , 2, 10)
I know the function I have supplied would be pretty useless when passed a multiple parameter function.. but I am just looking for how it can be done..
Thanks
As simple as this:
def sum (f: (Int, Int) => Int , a: Int, b: Int): Int = ???
Or a curried version:
def sum (f: Int => Int => Int , a: Int, b: Int): Int = ???
Although you can curry any function just calling f.curried