Based on below examples of defining functions what is the best use of 2 and 3 in different scenarios?
def sum(x: Int, y: Int): Int = { x+y }
This is a function definition with arguments, return type and function body
val sum = (x: Int, y: Int) => { x+y }
This seems like an assignment of lambda function to a variable, why return type is never defined here?
val sum: (Int, Int) => Int = (x,y) => { x+y }
This is defining a function as a type?
I don't understand how this works!
All 3 functions when invoked will yield the same result:
scala> sum(1,2)
Int = 3
def sum(x: Int, y: Int): Int = { x+y }
This is a function definition with arguments, return type and function body
This is not a function definition. This is a method definition. Functions and methods are fundamentally different. Functions are objects, methods are not. (Methods belong to objects.) Methods can be polymorphic, functions can't.
val sum = (x: Int, y: Int) => { x+y }
This seems like an assignment of lambda function to a variable, why return type is never defined here?
Are you asking why the type of sum isn't declared or why the return type of the function literal isn't declared? The return type of the function literal isn't declared because there is no way in the syntax to do so. You simply cannot declare the return type of a function literal, it is always inferred. The type of sum isn't declared because it is not necessary: it can be inferred to be the same as the type of the function literal, i.e. Function2[Int, Int, Int].
Think val foo = "Hello".
val sum: (Int, Int) => Int = (x,y) => { x+y }
This is defining a function as a type?
No. This is the exact same thing as 2., except that here the type of sum is explicitly declared (as (Int, Int) => Int which is syntactic sugar for Function[Int, Int, Int]) instead of inferred. Since the type of sum is known, you can leave off the types of the function parameters, because they can be inferred from the context.
Think val foo: String = "Hello".
In line 2, scala compiler inferences type of lambda function.
val sum = (x: Int, y: Int) => { x + y }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
function value
x and y are type of Int, thus x + y is a Int type. In this case, type of sum is (Int, Int) => Int.
In line 3, it shows the type of sum - (Int, Int) => Int. sum indicates a function same with line 2.
val sum: (Int, Int) => Int = (x,y) => { x+y }
~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~
type function value
Right side of = is function signature and body. It receives two arguments called x and y. Its body is x + y.
Shortly, line 2 and line 3 are equivalent. Line 2 has no type of function value, but scala can inference its type. Line 3 has type of function value explicitly, and omits argument type of signature of function value.
this is about the difference between method and function. The useful link to show the difference is http://java.dzone.com/articles/revealing-scala-magician%E2%80%99s
I think in the 3rd way, you can understand it like a type T = (Int, Int) => Int and then do this : val sum: T = (x,y) => { x+y }
another thing is that if remove input arguments, method and function is different.
def sum: Int = { 3 } //call sum, get 3
val sum: () => Int = () => { 3 } //call sum, return a function, need to call sum() to get 3
Related
I have a program as below, I can run it without problem using sum(x=>x)(1,2) for example.
What I don't understand is that why we can write sumF at the very end line, without parameters? I don't find explications about this.
Thanks.
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
}
The return value of the sum function is a function of type
(Int, Int) => Int
which is what sumF is
In Scala, if there is no return then the last expression is taken to be the return value. So, if the last expression is what you want to return, then you can omit the return keyword
What you are looking at is a higher order function. sum is a function that takes in a function f as its parameter and returns an arity 2 function that takes 2 ints and returns an Int (which is the exact type signature of sumF).
So i got the following function after some trial and error and research in our Textbook i could come up with a solution.
def prodC1(f : Int => Int) : (Int, Int) => Int = {
def prodA1(a : Int, b : Int) : Int =
if(a > b) 1 else f(a) * prodA1(a+1, b)
prodA1 // Why do i need this line here
}
If I don't put that there i get a Type mismatch, could someone elaborate/explain the requirement for this Line?
So there are a lot of things which you need to know to actually understand the answer to this.
In Scala any def is a method which is nothing more than one of the members of some object. methods are not first class members in Scala which also means that methods can not exist on their own.
In Scala, the value of anything needs to be an expression. Meaning the RHS for a def needs to be an expression like def abc = some-expression. Examples of expression are 1, 1 + 1, "xyz", anotherMethodCallWhichWillReturnAnExpression() etc.
And something like def abc = xxxxxx is not an expression in Scala language definition. And hence you can not do,
def prodC1(f : Int => Int) : (Int, Int) => Int = {
def prodA1(a : Int, b : Int) : Int =
if(a > b) 1 else f(a) * prodA1(a+1, b)
}
Now, when you are adding that extra line with prodA1, you are telling Scala to return this prodA1 which you just define. But remember prodA1 is just a method and hence can not exist on its own and hence can not actually be returned.
But functions are first class members in Scala (represented as instances of one of the various FunctionX classes) and hence can be returned.
In this case Scala will intelligently lift this method to become a function of type (Int, Int) => Int. This is called eta-expansion.
To understand things more in detail. You can open the Scala console and try the following.
scala> val s = "abc"
// s: String = abc
scala> val i = 10
// i: Int = 10
scala> def prodA1(a : Int, b : Int) : Int = if (a > b) 1 else a * prodA1(a+1, b)
// prodA1: (a: Int, b: Int)Int
Notice the difference between the output of Scala console for actual values and def. Now, if I try to use prodA1 as value of a val, I will get following error.
scala> val x = prodA1
// <console>:12: error: missing argument list for method prodA1
// Unapplied methods are only converted to functions when a function type is expected.
// You can make this conversion explicit by writing `prodA1 _` or `prodA1(_,_)` instead of `prodA1`.
// val x = prodA1
Scala is telling you that you can explicitly convert method to function by using a _. Lets try that.
scala> val x = prodA1 _
// x: (Int, Int) => Int = $$Lambda$1077/293669143#13278a41
Now x is a function of type (Int, Int) => Int.
Also, that first line Unapplied methods are only converted to functions when a function type is expected. is telling you about what actually happened in your case.
Since prodC1 was expected to return a function of type (Int, Int) => Int and you provided prodA1, Scala used eta-expansion to automatically convert your method to function.
Let's have a look at your return type.
def prodC1(f : Int => Int) : (Int, Int) => Int = {
def prodA1(a : Int, b : Int) : Int =
if(a > b) 1 else f(a) * prodA1(a+1, b)
prodA1 // Why do i need this line here
}
your return type is
(Int, Int) => Int
that is scala sugar for a Function2[Int, Int, Int]
where the first param is the type to the first param, the second param is the type for the second param and the last is the type for the return param
The return instance needs to be a function
prodA1 conforms to this type, meaning it is allowed to be returned.
Your function needs to return an instance of (Int, Int) => Int.
def prodA1(a : Int, b : Int) : Int =
if(a > b) 1 else f(a) * prodA1(a+1, b)
Creates a function of type (Int, Int) => Int with name prodA1 but the return type of defining an inner function does not create an instance of anything so the return type of the function is Unit.
Therefore you need to return the prodA1 which has the correct type..
Hi I am new to Scala and trying to call a higher order function sum_of from main class.I am getting "Cannot resolve reference sumOf with such signature error".
object SumOf {
def main(args: Array[String]) {
val y = sumOf(x=>x ,4,5)
println(y)
}
def sumOf(f: Int => Int)(a: Int, b: Int): Int = {
def loop(a: Int, acc: Int): Int =
if (a > b) acc
else loop(a + 1, f(a) + acc)
loop(a, 0)
}
}
sumOf is a curried function so it takes two arguments in the form of sumOf(x => x)(4,5) which is different from sumOf(x => x, 4,5). This is the reason you are getting an error.
Further, you can call it with only one argument sumOf(x => x) _ which returns another function that takes the second argument
(Int, Int) => Int = <function2> and return a function. This is more commonly known as partial function application.
Your sumOf method has two argument lists, and needs to be called with two argument lists.
val y = sumOf(x => x)(4, 5)
You can think of sumOf as a function which takes an Int => Int and returns a new function, which takes two Ints to return an Int.
This is slightly different from this question.
I want to define a function type that have default value defined.
Like this:
trait Foo {
type MyFunction = (Int, Option[Int] = 0) => Boolean
def checkInts(f: MyFunction)
}
Is it possible? If yes, how can I achieve this? If not, why?
Read here why you can't have default arguments in anonymous functions and how to make something similar - In Scala, can you make an anonymous function have a default argument?
But if you just need a way to pass a function taking 2 or 1 argument, you can always use simpler approach:
trait Foo {
type MyFunc1 = (Int) => Boolean
type MyFunc2 = (Int, Int) => Boolean
def checkInts(f: MyFunc1)
def checkInts(f: MyFunc2)
// common code of checkInts could be in some private method
}
Based on my knowledge so far you cannot define a type with default parameters. A type is a type.
What you can do is define a partially applied function.
Taking as an example the following function:
scala> def factorOf(x: Int, y: Int) = y % x == 0
factorOf: (x: Int, y: Int)Boolean
If you want a shortcut to the function without retaining any parameters, you can use the wildcard operator (_) assignment
scala> val f = factorOf _
f: (Int, Int) => Boolean = <function2>
scala> val x = f(7, 20)
x: Boolean = false
If you want to retain some of the parameters, you can partially apply the function by using the wildcard operator to take the place of one of the parameters. The wildcard operator here requires an explicit type, because it is used to generate a function value with a declared input type:
scala> val multipleOf3 = factorOf(3, _: Int)
multipleOf3: Int => Boolean = <function1>
scala> val y = multipleOf3(78)
y: Boolean = true
The new function value, multipleOf3, is a partially applied function, because it contains some but not all of the parameters for the factorOf() function.
A cleaner way to partially apply functions is to use functions with multiple parameter lists. This is a technique
known as currying the function:
scala> def factorOf(x: Int)(y: Int) = y % x == 0
factorOf: (x: Int)(y: Int)Boolean
scala> val isEven = factorOf(2) _
isEven: Int => Boolean = <function1>
scala> val z = isEven(32)
z: Boolean = true
Given the
def sum(a: Int, b: Int) = a + b
val add7 = sum(7, _)
// compiler complains missing $x1's type for $x1 => sum(7, $x1)
val add8 = sum(8, _: Int)
// fine
And curried sum can do this without type declaration .
def sum_curry(a: Int)(b: Int) = a + b
val add9 = sum_curry(9)(_)
// fine
But it's not a generic function, what sum's parameter types can be known and it is already there.
Why cannot Scala know the $x1's type from b: Int in sum's signature?
The compiler needs to know the data types of function arguments to map a function call to exactly one function definition (out of many overloaded function definition of with same name)
It will become ambiguous if we try a reverse mapping from function definition to function call to determine the type of a parameter in function call.
Eta expression can convert this to a value type (Int, Int) => Int only when:
_ as in place of the argument of list
val f = sum _
or, you just omit the argument list.
val f :(Int, Int) => Int = sum
and specify its type.
or use each _
val f = sum(_ , _)
As you can see, sum(7, _) cannot satisfy any of above.