I imagined this would work. Am I doing something clearly wrong?
val apply = (f: Any => Any, v: Any) => f(v)
val square = (x: Int) => x * x
I imagined apply(square, 10) would result in 100.
But I get an error:
:15: error: type mismatch;
found : Int => Int
required: Any => Any
apply(square, 100)
What I am missing here?
Functions are covariant in their return types, but contravariant in arguments.
Int => Int is a subclass of Int => Any, but not of Any => Int or Any => Any (if it was, you could use in a context where, for example, a String parameter is passed in, and it would not be able to handle it, because it wants an Int).
Cosider this:
val foo: Function[Int, Int] = { x => x * x }
def bar(f: Any => Any)(arg: Any): Any = f(arg)
bar(foo)("foo") //???
The if Int => Int was a subclass of Any => Any, then the last line would be valid. But it cannot be, because it would result in foo being called with a String parameter.
Note, on the other hand, that Any => Int is a subclass of Int => Int (you can use the former anywhere the latter is required). This is what being "contravariant" means.
Related
I'm looking at this sample code and after entering it in the scala repl I can see how it works.
val twice: Int => Int =
x => x * 2
This is similar:
val parse: String => Option[Int] =
s => if(s.matches("-?[0-9]+")) Some(s.toInt) else None
Can someone please deconstruct the above method and explain how this works?
I can see the name twice or parse, followed by the type which is Int => Int or String => Option[Int].
Now in the 2nd line of both functions you have a variable x or s. I can only assume this is the parameter.
Also if you can expand on what scala features allow a function to be written like this.
Thanks!
The expected type of value
x => x * 2
is
Int => Int
which de-sugars to
Function1[Int, Int]
hence function definition
val twice: Int => Int = x => x * 2
is equivalent to
val twice: Function1[Int, Int] = new Function1[Int, Int] {
override def apply(x: Int) = x * 2
}
as per SLS 6.3 Anonymous Functions.
when defining method in Scala, I found this
def method1: Int => Int = (j: Int) => j // works
def method2: Int => Int = j => j // works
def method3: Int => Int = j: Int => j // error
def method4: Int => Int = {j: Int => j} // works
Can anyone explain why method3 does not work? Is there any ambiguity in it?
One possible explanation is indeed that this restriction avoids ambiguity: x: A => B could be understood as an anonymous function that takes a parameter x of type A and returns the object B. Or it could be understood as "casting" a variable x to the type A => B. It is very rare that both of these would be valid programs, but not impossible. Consider:
class Foo(val n: Int)
val Foo = new Foo(0)
val j: Int => Foo = new Foo(_)
def method1: Int => Foo = (j: Int) => Foo
def method2: Int => Foo = j: Int => Foo
println(method1(1).n)
println(method2(1).n)
This actually compiles and prints:
0
1
All of these variants are covered by Anonymous Functions section of the specification. The relevant part is
In the case of a single untyped formal parameter, (x) => e
can be abbreviated to
x => e. If an anonymous function (x : T) => e
with a single typed parameter appears as the result expression of a block, it can be abbreviated to
x: T => e.
In method3, the function isn't the result expression of a block; in method4 it is.
EDIT: oops, presumably you meant why the limitation is there. I'll leave this answer for now as stating what the limitation is exactly, and remove it if anyone gives a better answer.
Consider following code:
val x: Any = 3 // Int assignable to Any
def k(x:Any){ 3 }
println(k(2)) // Int assignable to Any
def g(h: Any => Any): Unit = h()
def f = (x:Int) => 3
println(g(f)) // type mismatch error: Int => Int not assignable to Any => Any
Questions:
Why is Int assignable to Any, but Int => Int is not?
How to make this work? How to declare a function type that accepts and returns any type of value?
Edit:
Thanks to GPI, it could be made to work like this:
def g = (x:Int) => x*x
def holder[In, Out](f: In => Out, v:In) = { f(v) }
println(holder(g, 3))
Well your assertions are not totally exact.
E.g.a function of type Int => Int is indeed an Any:
scala> val iToi = (input: Int) => input
iToi: Int => Int = <function1>
scala> iToi(3)
res0: Int = 3
scala> val test: Any = iToi
test: Any = <function1>
The issue you have is indeed that a Int => Int is not a Any => Any but this one is easy to understand :
A Any => Any function accepts anything as an argument, for example, a String.
A Int => Int does not accept a String as an argument
Therefore it should not, and is not, possible to take a Int => Int and "cast" it to a Any => Any.
The otherway around
A Any => Any returns anyting as a result, it can return a String or an Int.
A Int => Int returns an Int.
If we restrict ourselves to a view of the result side of the function, they are compatible.
And indeed, we can say :
scala> val test2: Int => Any = iToi
test2: Int => Any = <function1>
This works.
One could write a generic function accepting any kind of function this way (but there are many more I'd bet are better, I'm not that good in Scala yet :-) ) :
scala> def holder[In, Out](f: In => Out) = { f.toString }
holder: [In, Out](f: In => Out)String
scala> holder(iToi)
res0: String = <function1>
When you deal with T => R function, in reality you have object of class
Function1[#scala.specialized -T1, #scala.specialized +R]
with two class parameters.
First parameter (T in our case) is in contravariant position (minus in front of T1), so you can not provide sub type when it wants super type.
So either change signature of f to def f = (x:Any) => 3
or alternatively parameter of g to Int => Any
Here is a function to memoize /cache intermediate result :
def memoize[I, O](f: I => O) = new scala.collection.mutable.HashMap[I, O]() {
override def apply(key: I): O = getOrElseUpdate(key, f(key))
}
This works fine for code like below,
val double: Int=>Int = memoize {
_*2
}
However, when I try to use tuple as input parameter(I) it shows compile time error,
val isGivenNumIsHead:(List[Int], Int) => Boolean = memoize {
case (Nil, _) => false
case (a:: as, n) => a == n
}
Compile time error is :
Expression of type mutable.HashMap[Nothing, Boolean] {def apply(key: Nothing): Boolean} doesn't conform to expected type (List[Int], Int) => Boolean
Is this something related to erasure.
How do i fix it ?
I am assuming you want to use the tuple as the key in the HashMap. With that in mind, here is the explanation.
The actual return type of memoize is scala.collection.mutable.HashMap[_,_] . That is being assigned to double which is of type Int => Int or Function1[Int,Int] ( a function that takes an integer and gives an interger). The compiler doesnt throw an error because mutable.HashMap extends scala.collection.mutable.MapLike which in turn extends scala.collection.MapLike which in turn extends scala.PartialFunction[A, B] which in turn extends scala.Function1[A, B]. Hence there is no compilation error.
On the other hand, the syntax for functions taking one parameter and returning one value is val functionName : A => B = a => {return b} or can be written as val function : (A) => B = a => {return b} or val function: (A => B) = a => {return b}. You have used the second method. In that case, the value of A should be of single type. You have used List[Int],Int which is not a single type. Note that I intentionally removed the brackets. So in order to make that as a single type and to pass it as a tuple, you have to use one more set of brackets. The correct syntax would be
val isGivenNumIsHead:((List[Int], Int)) => Boolean = memoize {
case (Nil, _) => false
case (a:: as, n) => a == n
}
Note the usage of additional brackets to make it a tuple.
I have following function with parameter lists:
def foo(a:Int, b:Int)(x:Int)(y:Int) = a * b + x - y
when I put the command on the relp
foo _
it shows me
res5: (Int, Int) => Int => (Int => Int) = <function2>
The first part expects two int parameters and then I do not know anymore how to read continue.
I can use the function like
foo(5,5)(10)(10)
but I do not know how to read it!
In general, A => B is the type of an anonymous function that, when given an argument of
type A, returns a value of type B.
Now, the type
(Int, Int) => Int => (Int => Int)
might look less confusing when you add some parenthesis:
(Int, Int) => (Int => (Int => Int))
As a start, just break it down to
(Int, Int) => (… => …)
i.e. a function that, given two Int, returns another function. The
function that is returned has type
(Int => (Int => Int))
i.e. a function that, given an Int, returns another function that, given an Int,
returns an Int.
It's easy. (Int, Int) => Int => (Int => Int) means that 2 first steps returns a function that will take some arguments. For example:
(Int, Int) => Function that return
(Int) => Function that return
(Int) => Int
Why is it useful? Because when you have a function that take a function as parameter in of it's arguments list you can omit parentheses and use curly braces.
def someFunStuff(fun: Int)(stuff: Int => Int) = {
fun*stuff(fun)
}
someFunStuff(2) { x =>
//Do some fun stuff
x * 2 / x
}
If you want to know a little bit more, please read Chapter 9.4 programming in Scala second edition.