After having discovered that currying multi parameter-groups method is possible, I am trying to get a partially applied function which requires implicit parameters.
It seams not possible to do so. If not could you explain me why ?
scala> def sum(a: Int)(implicit b: Int): Int = { a+b }
sum: (a: Int)(implicit b: Int)Int
scala> sum(3)(4)
res12: Int = 7
scala> val partFunc2 = sum _
<console>:8: error: could not find implicit value for parameter b: Int
val partFunc2 = sum _
^
I use a singleton object to create this partially applied function and I want to use it in a scope where the implicit int is defined.
That is because you don't have an implicit Int in scope. See:
scala> def foo(x: Int)(implicit y: Int) = x + y
foo: (x: Int)(implicit y: Int)Int
scala> foo _
<console>:9: error: could not find implicit value for parameter y: Int
foo _
^
scala> implicit val b = 2
b: Int = 2
scala> foo _
res1: Int => Int = <function1>
The implicit gets replaced with a real value by the compiler. If you curry the method the result is a function and functions can't have implicit parameters, so the compiler has to insert the value at the time you curry the method.
edit:
For your use case, why don't you try something like:
object Foo {
def partialSum(implicit x: Int) = sum(3)(x)
}
scala> object MySingleton {
| def sum(a: Int)(implicit b: Int): Int = { a+b }
|
|
| def caller(a: Int) = {
| implicit val b = 3; // This allows you to define the partial below
| def pf = sum _ // and call sum()() without repeating the arg list.
| pf.apply(a)
| }
| }
defined module MySingleton
scala> MySingleton.caller(10)
res10: Int = 13
Related
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
I'm trying to write a tail recursive function in the below way, but the compiler is throwing an error:
Too many arguments for method apply: (v1: Int)Int in trait Function1
else factorial(x-1, x*acc)
I had tried replacing Function1 with Function2 and gave Function2[Int, Int, Int] = new Function2[Int, Int, Int]
But it still threw me the same error. Can someone point out where i'm going wrong?
import scala.annotation.tailrec
var factorial: Function1[Int, Int] = new Function1[Int, Int] {
#tailrec override def apply (x:Int, acc:Int=1): Int = {
if (x<=1) acc
else factorial(x-1, x*acc)
}
}
factorial(5)
You apply inside Function1 must take only one param, when you are passing two.
You can rewrite it as follows:
var factorial: Function1[Int, Int] = new Function1[Int, Int] {
def apply (x:Int): Int = {
#tailrec def loop(x: Int, acc: Int = 1): Int = {
if (x<=1) acc
else loop(x-1, x*acc)
}
loop(x)
}
}
Function1 represents a function with a single parameter (the second one is for the output)
So you need to define your apply method with a single parameter, and then, inside it, do the recursion using a nested function:
import scala.annotation.tailrec
var factorial: Function1[Int, Int] = new Function1[Int, Int] {
override def apply(x: Int): Int = {
#tailrec
def go (x: Int, acc: Int = 1) : Int = {
if (x<=1) acc
else go(x-1, x*acc)
}
go(x)
}
}
factorial(5)
You can see this answer which is a great explanation of your issue. Your problem is you are trying to define apply as tail-recursive but you are not calling itself in the recursive call, you are calling factorial instead.
First off, you should use Function2 as your type for apply likewise:
import scala.annotation.tailrec
import scala.annotation.tailrec
var factorial: Function2[Int, Int, Int] = new Function2[Int, Int, Int] {
#tailrec override def apply (x:Int, acc:Int=1): Int = {
if (x<=1) acc
else apply(x-1, x * acc)
}
}
And then, if you get the error could not optimize #tailrec annotated method apply: it contains a recursive call targeting a supertype, you should call apply recursively as for a function to be tail recursive it always should be called exactly itself as the last statement.
scala> factorial(5, 1)
res3: Int = 120
Function2 take 3 type parameters. Last one is the output type.
Scala REPL
scala> :paste
// Entering paste mode (ctrl-D to finish)
val fac: Function2[Int, Int, Int] = new Function2[Int, Int, Int] {
def apply(v1: Int, v2: Int): Int = if (v1 == 1) v2 else apply(v1 - 1, v1 * v2)
}
// Exiting paste mode, now interpreting.
fac: (Int, Int) => Int = <function2>
scala> fac(5, 1)
res1: Int = 120
You can syntactic sugar (function syntax in scala using =>) instead of using interface/trait Function2.
scala> :paste
// Entering paste mode (ctrl-D to finish)
val fac: (Int, Int) => Int = (acc, c) => if (c == 1) acc else fac(acc * c, c - 1)
// Exiting paste mode, now interpreting.
fac: (Int, Int) => Int = $$Lambda$1092/1204822967#5c83ae01
scala> fac(1, 5)
res0: Int = 120
Or, if you like some syntactic sugar, you can write it:
val f: (Int) => BigInt = (x) => {
if (x <= 1) 1
else x * f(x - 1)
}
println(f(30))
Or true tail-recursive function:
val f: (Int) => BigInt = (x) => {
#tailrec
def helper(x: Int, acc: BigInt = 1): BigInt = {
if (x <= 1) acc
else helper(x - 1, x * acc)
}
helper(x)
}
println(f(30))
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 can I refer to one overload of a function? Does this require reflection?
----- Define two functions with the same signature
scala> def f( x:Int ) = x + 1
f: (x: Int)Int
scala> def g( x:Int ) = x + 2
g: (x: Int)Int
----- Define a function that returns one or the other
scala> def pick( a:Boolean ) = if (a) f _ else g _
pick: (a: Boolean)Int => Int
scala> pick(true)(0)
res24: Int = 1
scala> pick(false)(0)
res25: Int = 2
----- All good so far; now overload f to also take a String
scala> def f( x:String ) = x.toInt + 1
f: (x: String)Int
scala> def pick( a:Boolean ) = if (a) f _ else g _
pick: (a: Boolean)String with Int => Int
scala> pick(false)(0)
<console>:12: error: type mismatch;
found : Int(0)
required: String with Int
pick(false)(0)
^
I understand why this doesn't work. But how can I define pick to use the f that takes an Int, and ignore the f that takes a String?
Again, I don't want to write a function that calls either f or g. I want to write a function that returns f or g, which I can then call gazillions of times.
Just add a type annotation:
def pick( a:Boolean ) = if (a) f(_: Int) else g(_: Int)
Supplement: Don't be fooled by how the REPL constructs what it runs:
scala> :pa
// Entering paste mode (ctrl-D to finish)
object Foo {
def f(i: Int) = i.toString
def f(s: String) = s
def pick( a:Boolean ) = if (a) f _ else "nope"
}
// Exiting paste mode, now interpreting.
<console>:10: error: ambiguous reference to overloaded definition,
both method f in object Foo of type (s: String)String
and method f in object Foo of type (i: Int)String
match expected type ?
def pick( a:Boolean ) = if (a) f _ else "nope"
^
Using the REPL, the other answer to your question is, define the one you want last, because it becomes most specific:
scala> def f(s: String) = s
f: (s: String)String
scala> def f(i: Int) = i.toString
f: (i: Int)String
scala> f _
res0: Int => String = <function1>
Considering
object A {
def m(i: Int) = i
val m = (i: Int) => i * 2
}
one gets
scala> A.m(2)
<console>: error: ambiguous reference to overloaded definition,
both value m in object A of type => (Int) => Int
and method m in object A of type (i: Int)Int
match argument types (Int)
A.m(2)
^
Accessing the val can be done with
scala> val fun = A.m
fun: (Int) => Int = <function1>
scala> fun(2)
res: Int = 4
or
scala> A.m.apply(2)
res: Int = 4
but how would one access the def?
It is total rubbish (please, don't do this at home), but you can do it by assigning A to a variable of structural type, that has only the first m.
val x : { def m(i:Int):Int } = A
x.m(10)