Scala anonymous function syntax and return type - scala

I have found few kinds of anonymous function syntax in scala:
val m5_1 = { (n: Int) => n * 5 }
val m5_2 = (n: Int) => { n * 5 } : Int
val m5_3: Int => Int = n => { n * 5 }
Is that all types or some more syntax kinds present?
Are they all equivalent?
Which one is more/less preferred?
How can I specify the return type in m5_1 ?

I'll try to add to #pamu's answer:
Which one is more/less preferred?
I'd say the second variant is a bit uncommon. When the type inference is easily visible, you can go for the first, otherwise being explicit as in the third case is good. You don't need braces there, so a simpler variant is
val m5_3: Int => Int = n => n * 5
Or even
val m5_3: Int => Int = _ * 5
How can I specify the return type in m5_1 ?
The return type is Int => Int, so that is the same type annotation as you use in the third case:
val m5_1: Int => Int = { (n: Int) => n * 5 }
But then of course, you can let Scala use the type inference on the right hand side:
val m5_1: Int => Int = n => n * 5
And therefore this is identical to your third form.
Note that the : Int in the second form is not defining the type of m5_2, which is Int => Int and not Int. It simply tells Scala that the type of n * 5 is meant to be Int. This can aid you reading the code, but it doesn't actually change the way the type is inferred in this case. You can think of your second form of actually being:
val m5_2 = (n: Int) => {
val res = n * 5: Int // : Int redundant here because it is already inferred
res
}
Where val res = n * 5: Int has the same effect as val res: Int = n * 5

Is that all types or some more syntax kinds present ?
Lambda syntax requires the input parameter type to be known. If not compiler throws an error. In all the syntaxes you are trying to give this information. But return type can be inferred by the compiler.
Are they all equivalent?
All are equivalent
Which one is more/less preferred ?
The below one is recommended if you do not want to see explicit type annotation
val m5_1 = { (n: Int) => n * 5 }
How can I specify the return type in m5_1 ?
Return type is inferred from the last line of the lambda. The last line is n * 5 which of type Int. So, compiler infers the type for you. You can skip giving the type information explicitly

Well, the above answers have properly explained almost everything I guess. I just want to add one more variant that we could do here:
val m5_4 = {n=> n*5}:Int=>Int

Related

missing parameter type for expanded function (Scala)

Here's my function:
def sumOfSquaresOfOdd(in: Seq[Int]): Int = {
in.filter(_%2==1).map(_*_).reduce(_+_)
}
Why am I getting the error "missing parameter type for expanded function"?
map is accepting function with one parameter ((A) => B) while every _ placeholder represents a separate parameter of anonymous function (i.e. _ * _ is function with two parameters). You can use i => i * i lambda for your map function:
def sumOfSquaresOfOdd(in: Seq[Int]): Int = {
in.filter(_%2==1)
.map(i => i * i)
.reduce(_ + _)
}
Also you can use sum instead of reduce(_ + _) (note that sum will not throw for empty sequences while reduce will):
def sumOfSquaresOfOdd(in: Seq[Int]): Int = {
in.filter(_%2==1)
.map(i => i * i)
.sum
}
I guess because map wants a function of a single argument, and you ask it to call * with two arguments. Replace _ * _ with arg => arg * arg and retry.
"map" was called with a function with two parameters when it is expecting a function of one parameter. There's another small bug due to the use of "reduce" - it throws an exception if there aren't any odd Ints in the input Seq.
A better solution would be:
def sumOfSquaresOfOdd(in: Seq[Int]): Int =
in.filter(_ % 2 == 1) . map(x => x * x) . sum
You must be using Scala2. Scala3 gives a much better error message:
Error:
2 | in.filter(_%2==1).map(_*_).reduce(_+_)
| ^^^
| Wrong number of parameters, expected: 1
(Edited to reflect changes in the other answers to this question.)

Understanding Scala Currying

I am following a course from coursera where this example appears in the lecture but when I try and run it, it throws an error as follows:
missing argument list for method mapReduce in object HelloWorld
Unapplied methods are only converted to functions when a function type is expected.
You can make this conversion explicit by writing mapReduce _ or mapReduce(_,_,_)(_,_) instead of mapReduce.
var doo = mapReduce(x => x,(x,y)=>x*y,0)
Below is the code that I want to execute.
def mapReduce(map: Int => Int, combine: (Int,Int)=>Int,
zero: Int)(a: Int,b: Int): Int = {
if (a>b) zero
else combine(map(a), mapReduce(map,combine,zero)(a+1,b))
}
var doo = mapReduce(x => x, (x,y)=>x*y, 0)
println(doo(1,4))
mapReduce wants two argument lists, but your are giving it one.
Try this:
val doo = mapReduce(x => x, (x,y) => x*y, 0) _
or equivalently,
val doo = mapReduce(identity, _*_, 0) _
The _ in the end stands for the second argument list. It tells the compiler that you want the suffixed value to be taken as a functional value rather than an expression to be evaluated.
You can also give compiler a hint to make the conversion happen automatically by explicitly declaring the expected type of the expession:
val doo: (Int, Int) => Int = mapReduce(identity, _*_, 0)
And don't use vars. They are evil. Just pretend, there is no such keyword in scala, until you learn enough of the language to be able to recognize the extremely rare cases when it is actually needed.
You have to define a undescore parameter in order to create a curried function. Like this:
scala> var doo = mapReduce(x => x, (x,y)=>x*y, 0) _
doo: (Int, Int) => Int = <function2>
scala> println(doo(1,4))
0

How to use function with Any input

I have to define a second order function that takes as a parameter a function.
In my application, the input function may have any input type, but the output type has to be a specified one (suppose Int, it does not matter).
I define the second order function has:
def sof(f : (Any => Int) ) = {...}
Now, if I have a function f : Int => Int, and I call:
sof(f)
I get:
found : Int => Int
required: Any => Int
I guess I am misunderstanding the meaning of the Any type.
How can I make it work?
The parameters of functions in Scala are contravariant. That means that Int => Int is not a subtype of Any => Int, but vice-versa. Imagine the following: You pass a String to the Any => Int function (that is actually implemented by a Int => Int function). How would the Int => Int handle the String argument?
You shouldn't use Any there, but a type parameter such as:
def sof[A](f: A => Int) = {...}
However I don't think you can do much with that method. Probably you would want something like this:
def sof[A](a: A)(f: A => Int) = f(a)
// usage example
val x = sof("hello")(_.size * 2) // the result is 10
// you can also partially apply it to obtain other functions
val sizeDoubler: String => Int = sof(_)(_.size * 2)
val helloDoubleSize = sizeDoubler("hello") // the result is 10
This way you can pass any type to sof plus you'll have the compiler by your side to signal any strange behaviour. Using Any you lose this ability.
Final Note: In case the syntax I used to pass two parameters (the A value and the A => Int function) to a method looks strange to you that's called currying. If you Google it you'll find many good articles about it.

Specifying the lambda return type in Scala

Note: this is a theoretical question, I am not trying to fix anything, nor am I trying to achieve any effect for a practical purpose
When creating a lambda in Scala using the (arguments)=>expression syntax, can the return type be explicitly provided?
Lambdas are no different than methods on that they both are specified as expressions, but as far as I understand it, the return type of methods is defined easily with the def name(arguments): return type = expression syntax.
Consider this (illustrative) example:
def sequence(start: Int, next: Int=>Int): ()=>Int = {
var x: Int = start
//How can I denote that this function should return an integer?
() => {
var result: Int = x
x = next(x)
result
}
}
You can always declare the type of an expression by appending : and the type. So, for instance:
((x: Int) => x.toString): (Int => String)
This is useful if you, for instance, have a big complicated expression and you don't want to rely upon type inference to get the types straight.
{
if (foo(y)) x => Some(bar(x))
else x => None
}: (Int => Option[Bar])
// Without type ascription, need (x: Int)
But it's probably even clearer if you assign the result to a temporary variable with a specified type:
val fn: Int => Option[Bar] = {
if (foo(y)) x => Some(bar(x))
else _ => None
}
Let say you have this function:
def mulF(a: Int, b: Int): Long = {
a.toLong * b
}
The same function can be written as lambda with defined input and output types:
val mulLambda: (Int, Int) => Long = (x: Int, y: Int) => { x.toLong * y }
x => x:SomeType
Did not know the answer myself as I never had the need for it, but my gut feeling was that this will work. And trying it in a worksheet confirmed it.
Edit: I provided this answer before there was an example above. It is true that this is not needed in the concrete example. But in rare cases where you'd need it, the syntax I showed will work.

How is this type miss match?

HI I am new at Scala Trying to run this code:
class Number(x : Int){
var number = x
def inc(): Int = {
number => number + 1
}
}
But I get the following error: solution.scala:12: error: missing parameter type
number => number + 1
I dont know how to fix this.
Essentially, you can expicitly say what type you're expect:
def inc(): Int = {
number: Int => number + 1
}
BUT this won't compile, cause what you've defined is function, so:
def inc(): (Int) => Int = {
// some function that takes Int, calls it `number` and increment
number: Int => number + 1
}
would be closer,
BUT
it doesn't make sense and notice, that number you've defined has nothing in common with number variable inside class
-- that's why Scala compiler cannot infer type for you.
I think you have wanted to write something like:
def inc(): Int = {number += 1; number;}
// will take effect on number field
or
def inc(num: Int): Int = num + 1
or simply:
def inc = (x: Int) => x + 1
since Int return type is inferred, no need to specify it
As for dealing with mutability in the question, inc(1), inc(5), etc. are themselves transformed representations of the number passed to the class instance (i.e. they equate to "var number", but immutably so). No real need for mutability based on what we see here...