I am trying to pass the partial function as input to square function.
What is worng with the following code?
package PartialFunction
object PartialFunctionSum {
val yourConstant = 10
val pf: PartialFunction[(Int, Int), Int] = {
case (x, y) => x + y + yourConstant
}
def square(cb:(Int, Int) => Int): Unit = {
println(cb(5,10))
}
def main(args: Array[String]): Unit= {
square(pf)
}
}
A PartialFunction is a Function1 (a => b) and square needs a Function2 ((a,b) => c)
One way to accomplish what you want to do is changing cb type to Function1.
object PartialFunctionSum extends App {
val yourConstant = 10
val pf: PartialFunction[(Int, Int), Int] = {
case (x, y) => x + y + yourConstant
}
def square(cb:((Int, Int)) => Int): Unit = {
println(cb(5,10))
}
square(pf)
}
Also, anywhere where you need a FunctionX, you can define a PartialFunction, so
square {
case (x, y) => x + y + yourConstant
}
Or transform your PartialFunction in a Function2 with a lambda
square( pf.apply(_, _) )
Anywhere you need a function you can a pass a PartialFunction,
Your problem is with square definition:
def square(cb:(Int, Int) => Int): Unit = {
println(cb(5,10))
}
That means that cb is a function that receives two Ints and returns another Int.
Just change square signature as follows:
def square(cb: ((Int, Int)) => Int): Unit = {
println(cb(5 -> 10))
}
And now your types are compatible and the rest of your code works as you expected.
(Int, Int) => Int is an instance of Function2[Int, Int, Int](a Function that takes 2 Int parameters and returns an Int), not PartialFunction[(Int, Int), Int] (a partial function that takes an input of type (Int, Int) and returns an Int)
If you want to pass your parameters as a Tuple then:
def square(cb:PartialFunction[(Int, Int),Int]): Unit = {
println(cb((5,10)))
}
Example:
def square(cb:PartialFunction[(Int, Int),Int]): Unit = {
println(cb((5,10)))
}
square: (cb: PartialFunction[(Int, Int),Int])Unit
scala> square{case (i, j) => i * j}
50
Related
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
I just ran into a strange disparity between functions and objects (scala 2.10):
implicit def conv(c: Int => String) : (PrintStream => Int => Unit) = p => v => p.println(c(v))
def f(h: PrintStream => Int => Unit) : Unit = h(System.out)(1)
def a(x: Int) = x.toString
val b = (x: Int) => x.toString
// def main(args: Array[String]) = f(a) // fail
// def main(args: Array[String]) = f((x: Int) => x.toString) // fail
def main(args: Array[String]) = f(b) // ok
Why is there a difference between defs/lambda literals and lambda vals?
Update: apparently, the Problem does not occur for binary functions: Implicit conversion of a function to a second-order-function only works if the function to convert has at least two parameters
I checked this, and indeed the following code works:
implicit def conv(c: (Int,Unit) => String) : (PrintStream => Int => Unit) = p => v => p.println(c(v,()))
def f(h: PrintStream => Int => Unit) : Unit = h(System.out)(1)
def a(x: Int, y : Unit) = x.toString
val b = (x: Int, y : Unit) => x.toString
def main(args: Array[String]) = f(a) // ok
def main(args: Array[String]) = f((x: Int, y: Unit) => x.toString) // ok
def main(args: Array[String]) = f(b) // ok
Likewise, Nullary functions don't pose a problem, either:
implicit def conv(c: () => String) : (PrintStream => Int => Unit) = p => v => p.println(c())
def f(h: PrintStream => Int => Unit) : Unit = h(System.out)(1)
def a() = "1"
val b = () => "1"
def main(args: Array[String]) = f(a) // ok
def main(args: Array[String]) = f(() => "1") // ok
def main(args: Array[String]) = f(b) // ok
So, rephrasing the question: why does this not work for UNARY methods and functions?
Update: the problem also seems to be related to the target type (the type of f's argument h). The following also works (this time, in favour of "eta-expansion counts as hop", because we need to create a method value from a using _)
implicit def conv(c: Int => String) : Unit = ()
def f(h: Unit) : Unit = System.out.print("?")
def a(x: Int) = x.toString
val b = (x: Int) => x.toString
def main(args: Array[String]) = f(a _) // ok
def main(args: Array[String]) = f((x: Int) => x.toString) // ok
def main(args: Array[String]) = f(b) // ok
In scala defs are methods and are diffrent from functions.
scala> def a( x: Int, y: Int ): Int = x + y
a: (x: Int, y:Int)Int
scala> (x: Int, y: Int) => x + y
res0: (Int, Int) => Int = <function2>
You can convert a method to function by partially applying it.
scala> b _
res1: (Int, Int) => Int = <function2>
So.. you can do,
implicit def conv(c: Int => String) : (PrintStream => Int => Unit) = p => v => p.println(c(v))
def f(h: PrintStream => Int => Unit) : Unit = h(System.out)(1)
def a(x: Int) = x.toString
val af = a _
def main( args: Array[ String ] ) = f( af )
Alse, as #srgfed01 mentioned in his comment... for the second case the problem is that... they types are not explicitly specified, if you specify the type correctly... the second case will work.
scala> f( ( a => a.toString ): (Int => String) )
1
or
scala> f( ( _.toString ): (Int => String) )
1
Now, about differences between methods and functions...
You can call a method taking no arguments without parenthesis ()... but you can not call a function without ().
scala> def g() = 5
g: ()Int
scala> g
res15: Int = 5
scala> () => 5
res13: () => Int = <function0>
scala> res13
res14: () => Int = <function0>
scala> res13()
res15: 5
One of the most important reasons for methods being different from functions is because creators of Scala wanted seamless inter-interoperability with Java without being stuck with Java's limitations.
So methods (def) are very much similar to Java methods and keeping functions different from methods enabled them with limitless freedom to create Scala, the way they wanted.
Also... Another major difference is that methods can accept Type-classes where as functions can not. Basically you can have generic methods like
scala> :paste
trait Behave {
def behave
}
class A( elem: String ) extends Behave {
def behave() {
println( elem )
}
}
// Exiting paste mode, now interpreting.
defined trait Behave
defined class A
Now you can define a generic method,
scala> def check[ T <: Behave ]( t: T ): Unit = t.behave()
check: [T <: Behave](t: T)Unit
But you can not define a function like this,
scala> ( t: T ) => t.behave()
<console>:8: error: not found: type T
( t: T ) => t.behave()
or like this
scala> ( t: (T <: Behave) ) => t.behave()
<console>:1: error: ')' expected but '<:' found.
( t: (T <: A) ) => t.behave()
I defined a function foo like
def foo(f : (Int, Int) => Int) = f(1,2) // just calling with some default vals
and can invoke it like
foo(_+_)
But when i try to use the same way to invoke a function that takes IntPair(custom type) as param then i receive the error
error: wrong number of parameters; expected = 1
What is the correct syntax to invoke it
Sample Code
type IntPair = (Int, Int)
def sum(f: (IntPair) => Int): (IntPair) => IntPair = {
def iter(pair: IntPair): IntPair = {
val n = readLine()
print(s"$n+")
if (n != "q") {
val (total, accum) = pair
val p: IntPair = (f(n.toInt, total), accum + 1)
iter(p)
} else {
pair
}
}
iter
}
i can invoke like
val f = sum((p : IntPair) => p._1 + p._2) // i want to use here _ syntax
f((0,0))
but not like
val f = sum((_._1 + _._2)) //gives error
scala> def sum(p: ((Int, Int)) => Int) = p((2, 3))
sum: (p: ((Int, Int)) => Int)Int
scala> sum(Function.tupled(_+_))
res4: Int = 5
In Scala parameter lists and tuples are not unified, thus you can't simply pass a tuple to a function that expects multiple arguments.
sum(_._1 + _._2) means sum((x,y) => x._1 + y._2) btw, hence the error.
Why does andThen only exist for single argument functions in Scala?
The following code works:
val double = (x: Int) => x * 2
val timesFour = double andThen double
But why is there no andThen method for multi argument functions?
val multiply = (x: Int, y: Int) => x * y
val multiplyAndDouble = multiply andThen double
<console>:10: error: value andThen is not a member of (Int, Int) => Int
Surely it is trivial to add this method. Is there a reason it been omitted from the standard library?
I have just noticed it is easy to work around with the following:
val multiplyAndDouble = multiply.tupled andThen double
val res = multiplyAndDouble(1, 3) // res = 6
I can't speak as to why Function2 doesn't supply and andThen, but Scalaz defines Functor instances for functions of various arities where map is equivalent to andThen, meaning you could write
val multiplyAndDouble = multiply map double
There is a similar question here:
Scala API 2.10.*: Function2.andThen what happened to?, but there is also no answer. In my opinion it is possible. Here is working example for Scala 2.11.1:
object TestFunction2 {
def main(args: Array[String]): Unit = {
val double = (x: Int) => x * 2
val timesFour = double andThen double
println(timesFour(2)) // prints 8
val multiply = (x: Int, y: Int) => x * y
val multiplyAndDouble = multiply andThen double
println(multiplyAndDouble(1, 3)) // prints 6
}
implicit def toFunc2(function2: Function2[Int, Int, Int]): Func2[Int, Int, Int] = {
new Func2[Int, Int, Int] {
def apply(v1: Int, v2: Int): Int = function2(v1, v2)
}
}
}
trait Func2[-T1, -T2, +R] extends Function2[T1, T2, R] {
def andThen[A](g: R => A): (T1, T2) => A = { (x, y) => g(apply(x, y)) }
}
Another way to write theons's answer is to use:
val multiplyAndDouble = double compose multiply.tupled
val result = multiplyAndDouble(2, 6) // res 24
I want IMPLICIT args in a higher order function, like:
func(arg1) { implicit (x, y) => x * y }
But the compiler says:
error: expected start of definition
val a = func("2", "4") { implicit (x, y) =>
^
java version "1.7.0_40"
Scala code runner version 2.10.2-RC2 -- Copyright 2002-2013, LAMP/EPFL
The runnable sample code:
object Test extends App {
new Test().run
}
class Test {
def run = {
val a = func("2", "4") { (x, y) => // It's OK
x * y
}
println("a: " + a)
val b = gunc("2", "4") { implicit x => { implicit y => // It's OK
x * y
}}
println("b: " + b)
}
def func(x: String, y: String)(f: (Int, Int) => Int) = f(x.toInt, y.toInt)
def gunc(x: String, y: String)(g: Int => Int => Int) = g(x.toInt)(y.toInt)
def hunc(x: String, y: String)(h: Tuple2[Int, Int] => Int) = h((x.toInt, y.toInt))
}
[ADD COMMENT]
I wonder...
We can declare as "implicit x => ..." with one arg.
It seems there is no way to declare two implicit args.
Try adding:
val c = hunc("2", "4") { implicit pair => pair._1 * pair._2 }
When you say implicit y => y * 2 you're not
declaring an implicit argument but mark the function as implicit,
so you make an analog to this:
implicit val f1 = (y: Int) => y * 2
def func1(x: String, y: String)(f: Int => Int) = f(1)
func1("", "")(f1)
When you want to mark a function with two
arguments as implicit you can do it this way:
implicit val f2 = (x: Int, y: Int) => y * 2
def func2(x: String, y: String)(f: (Int, Int) => Int) = f(1, 2)
func2("", "")(f2)
But you cannot do it so:
func2("", "")(implicit (x, y) => x), in this particular case I just don't see any meaning to use implicits.
Also you can see this question, maybe you'll find some useful information there