I have this code:
for( i <- 0 to 8){
((numbers(i) - i)/3).abs + ((numbers(i) - i)%3).abs
}
and I would like to do, as the title says, something like this
for( i <- 0 to 8){
by3(numbers(i), i, /) + by3(numbers(i), i, %)
}
def by3(a: Int, b: Int, op: Int => Int) = ((a - b) op 3).abs
and probably also use a partially applied function for it.. but by now this would be possible to achieve? How?
First, you need to correctly define op as a function (specifically, a Function2)
def operate(a: Int, b: Int, op: (Int, Int) => Int ) : Int = (op ((a - b), 3)).abs
Operators in Scala are actually methods: + is a method of Int(and Long, Double, ...) in Scala OO foundation. Then, to pass a operator (method) as a function, you can lift it using the underscore notation:
operate(5, 3, _ + _)
To get rid of the underscores you need to define the functions as values.
val / = (a:Int, b: Int) => a / b
val % = (a:Int, b: Int) => a % b
def by3(a: Int, b: Int, fn: (Int, Int) => Int): Int = fn(a - b, 3).abs
(0 to 8).foreach(i => by3(numbers(i), i, /) + by3(numbers(i), i, %))
Edited/Update:
Being concise, the shortest way to do it is:
def doStuff(a: Int, b: Int, op: (Int, Int) => Int) = {op(a - b, 3).abs}
doStuff(4,1,_%_)
So you can doStuff(numbers(i), i, _ / _) + doStuff(numbers(i), i, _ % _)
Related
I'm trying to understand the difference between those 3. In particular their type.
val func0: (Int, Int, Int) => Int = _ + _ + _
//func0: (Int, Int, Int) => Int = <function>
def method0 (a: Int, b:Int, c:Int) = (_:Int) + (_:Int) + (_:Int)
//method0: (a: Int, b: Int, c: Int)(Int, Int, Int) => Int
def method1 (a: Int, b:Int, c:Int) = a + b + c
//method1: (a: Int, b: Int, c: Int)Int
Is there a rule that says that "_" can only be used in function body and not method body ?
Can't understand the type of method0, definitely not like func0 ....
Why is it different from method1 ?
method0 is a method that takes 3 parameters and return a function that takes a 3-tuples and return an int ? How is that possible ?
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.
I have a function in scala that I wonder if it's possible to make into a tail recursive function.
def get_f(f: Int => Int, x: Int, y: Int): Int = x match {
case 0 => y
case _ => f(get_f(f, x - 1, y))
}
I see that this function applies f function to result recursivly, x times. It's the same as applying it to y, x times. Also I suggest you to use if else instead of pattern matching.
#tailrec
def get_f(f: Int => Int, x: Int, y: Int): Int =
if(x == 0) y
else get_f(f, x - 1, f(y))
Add #tailrec annotation to ensure that it is tail recursive
It is possible but the way you've constructed it means you're going to have to use a Trampolined style to make it work:
import scala.util.control.TailCalls._
def get_f(f: Int => Int, x: Int, y: Int): TailRec[Int] = x match {
case 0 => done(y)
case _ => tailcall(get_f(f, x - 1, y)).map(f)
}
val answer = get_f(_+1, 0, 24).result
You can read about TailRec here or for more advanced study, this paper.
Let's start with reducing number of parameters from your non-tailrec version to make it clear what it actually does:
def get_f(f: Int => Int, x: Int, y: Int) = {
def get_f_impl(x: Int): Int = x match {
case 0 => y
case _ => f(get_f_impl(x - 1))
}
get_f_impl(x)
}
The idea is that actually you apply f-function x-times to initial value y. So, it becomes clear that you can do something like this in order to make it tail-recursive:
def get_f(f: Int => Int, x: Int, y: Int) = {
#tailrec def get_f_impl(acc: Int, x: Int): Int =
if (x == 0) acc else get_f_impl(f(acc), x - 1)
get_f_impl(y, x)
}
REPL investigation:
Your original implementation:
scala> get_f(_ + 1, 4, 0)
res6: Int = 4
Your implementation (with params optimisation):
scala> get_f(_ + 1, 4, 0)
res0: Int = 4
Tailrec implementation:
scala> get_f(_ + 1, 4, 0)
res3: Int = 4
P.S. For more complex cases trampolines might fit: https://espinhogr.github.io/scala/2015/07/12/trampolines-in-scala.html
P.S.2 You can also try:
Scala - compose function n times
#adamw noticed that it will allocate n-sized list, so might not be very efficient
Endo.mulitply in scalaz (your f: Int => Int is actually an endomorphism): https://stackoverflow.com/a/7530783/1809978 - not sure about efficiency
I'll add that you can achieve the same result by using foldLeft on Range, like this:
def get_f(f: Int => Int, x: Int, y: Int) =
(0 until x).foldLeft(y)((acc, _) => f(acc))
In line with previous responses
def get_f2( f: Int => Int, x: Int, y: Int) : Int = {
def tail(y: Int, x: Int)(f: Int => Int) : Int = {
x match {
case 0 => y
case _ => tail(f(y), x - 1)(f) : Int
}
}
tail(y, x)(f)
}
The following two higher-order functions yield the same result, but I'm having trouble understanding the difference between the two. In fact, I don't understand 1). How can a function have two sets of ()?
1)
def sum(f: Int => Int) (a: Int, b: Int) = {
def loop(a: Int, acc: Int) : Int =
if (a > b) acc
else loop (a + 1, f(a) + acc)
loop (a, 0)
}
2)
def sum(f: Int => Int, a: Int, b: Int) = {
def loop(a: Int, acc: Int) : Int =
if (a > b) acc
else loop (a + 1, f(a) + acc)
loop (a, 0)
}
The first function is curried. Meaning you can partially apply it more easily. If you only use the first parameter list the function returns another function with the signature (Int, Int) => Int.
This is really useful if you need to pass a function with a specific function signature to higher order functions like map or reduce.
In other functional programming languages like Haskell, all functions are curried by default.
I wrote a whole blog post on this topic in case you're interested. You can read it right here.
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