Tried this in Eclipse worksheet (2.10.1):
def a = { println("In a"); 3 } //> a: => Int
def b() = { println("In b"); 3 } //> b: ()Int
val c = () => { println("In c"); 3 } //> c : () => Int = <function0>
def test_type(x: => Int) = x //> test_type: (x: => Int)Int
test_type(a) //> In a
//| res0: Int = 3
b() //> In b
//| res1: Int = 3
c() //> In c
//| res2: Int = 3
test_type(b) //> In b
//| res3: Int = 3
// test_type(c) *** Doesn't compile
I'm definitely missing something. What's the difference between a, b and c? Looks to me that a is a "by-name" substitute for val a = 3 (uniform access principle?) so I can't call a(), but why b and c have different types? I can call b without parenthesis too (i.e. b will be evaluated to a result) as well as a, and b will be converted to "by-name" when calling test_type, but c won't and c without parameters will be evaluated to the function itself (which looks reasonable).
And one more question, Martin Odersky in his online course is saying that any anonymous function like () => 3 can be substituted with { def f() = 3; f } if I got it right, but these two expressions have different types and evaluation rules, first will be evaluated to a function, second - to function result, e.g.:
val f2 = { def f() = 3; f } //> f2 : Int = 3
There are many cases where Scala treats methods and functions differently. The uniform access principle applies to method invocation, since methods are often used to mimic fields on objects, but not to function application.
While b is a method of type ()Int, the code b will invoke the method when evaluated, unless the compiler expected a function type where b was used, in which case it will eta-expand the method to a function.
Since c is a function of type () => Int, applying it needs to be explicit in all contexts. So, test_type(c()) should compile.
The "by-name"-ness of x: => Int doesn't affect these inference/application rules; it only affects when the parameter might be evaluated.
scala> object Foo {
| def f(): Int = 123
| val g: () => Int = () => 123
| }
defined module Foo
scala> Foo.f
res0: Int = 123
scala> Foo.g
res1: () => Int = <function0>
scala> Foo.g()
res2: Int = 123
scala> (Foo.f: () => Int) // force eta-expansion by explicitly specifying function type
res3: () => Int = <function0>
Related
Given
scala> def method(x: Int) = x
method: (x: Int)Int
scala> val func = (x: Int) => x
func: Int => Int = <function1>
Consider the following code:
scala> method _
res0: Int => Int = <function1>
scala> func(_)
res1: Int => Int = <function1>
scala> func _
res2: () => Int => Int = <function0>
I can understand that res0 is eta expansion and res1 is equivalent to lambda function (x) => func(x). But I cannot figure out the output of res2. Could anyone please explain that for me?
This is actually a bit tricky. First, let's see what happens outside REPL:
It doesn't work when func is a local variable:
object Main extends App {
def foo() = {
val f = (_: Int) + 1
f _
}
println(foo())
}
[error] /tmp/rendereraEZGWf9f1Q/src/main/scala/test.scala:8: _ must follow method; cannot follow Int => Int
[error] f _
[error] ^
But if you put it outside def foo, it compiles:
object Main extends App {
val f = (_: Int) + 1
val f1 = f _
println(f1)
}
because f is both a field of Main and a method without arguments which returns the value of this field.
The final piece is that REPL wraps each line into an object (because Scala doesn't allow code to appear outside a trait/class/object), so
scala> val func = (x: Int) => x
func: Int => Int = <function1>
is really something like
object Line1 {
val func = (x: Int) => x
}
import Line1._
// print result
So func on the next line refers to Line1.func which is a method and so can be eta-expanded.
You've used the eta Expansion to turn res2 into a function that takes 0 parameters and returns a function that takes a single parameter.
res2: () => Int => Int = <function0>
So you can now do this:
val zero = func _
val f: Int => Int = zero()
To answer your question about res2 - the appended underscore _ syntax is used to partially apply a function.
So.
scala> func _
Means you have partially applied your <function1>.
This results in a new curried form, the first function of which takes zero arguments (hence <function0>)
() =>
Which returns your original <function1> which takes 1 argument.
Int => Int = <function1>
The complete result being the chain of functions.
res2: () => Int => Int = <function0>
The rule that might be useful for you to remember is that functions associate to the right so the following are equivalent.
() => Int => Int
() => (Int => Int)
This other post might be useful reading for you.
val func1 = func _
This returns a function0 which takes no arguments and returns the func function.
You can use this like:
func1()(2) // outputs 2
You can continue doing this kind of expansion ad infinitum:
val func2 = func1 _
func2()()(2) // outputs 2
I am trying to declare a simple method in scala with multiple parameter lists.
These two work.
scala> def add(a:Int, b:Int) = a+ b
add: (a: Int, b: Int)Int
scala> def add(a:Int)(b:Int) = a + b
add: (a: Int)(b: Int)Int
This does not...
scala> val add = (a:Int)(b:Int)=>a + b
<console>:1: error: not a legal formal parameter.
Note: Tuples cannot be directly destructured in method or function parameters.
Either create a single parameter accepting the Tuple1,
or consider a pattern matching anonymous function: `{ case (param1, param1) => ... }
val add = (a:Int)(b:Int)=>a + b
But why ... all I am trying to do is to assign a anonymous function which takes multiple parameter lists to a value. that works with a single parameter list but not with multiple parameter lists.
It's just a matter of syntax when declaring the curried arguments.
scala> val add = (a:Int) => (b:Int) => a + b
add: Int => (Int => Int) = <function1>
scala> add(4)
res5: Int => Int = <function1>
scala> res5(9)
res6: Int = 13
Example of anonymous usage:
scala> def doit(f: Int => Int => String): String = f(2)(5)
doit: (f: Int => (Int => String))String
scala> doit(a => b => (a+b).toString)
res8: String = 7
Scala allows functions with no parameter lists to be invoked without parentheses:
scala> def theAnswer() = 42
theAnswer: ()Int
scala> theAnswer
res5: Int = 42
How would I construct a scala expression that evaluates to the function theAnswer itself, rather than the result of theAnswer? Or in other words, how would I modify the expression theAnswer, so that the result was of type () => Int, and not type Int?
It can be done with:
scala> theAnswer _
res0: () => Int = <function0>
From the answer to the similar question:
The rule is actually simple: you have to write the _ whenever the
compiler is not explicitly expecting a Function object.
This call will create the new instance every time, because you're "converting" method to function (what is called "ETA expansion").
Simply:
scala> val f = () => theAnswer
f: () => Int = <function0>
scala> val g = theAnswer _
g: () => Int = <function0>
In Scala, defining a function whose parameter is called by name is like this:
def f(x: => R)
I think => R means the a function whose parameters are empty and return value type is R. But when I pass a function whose type is not => R into f, such as R => R, I find it still works. The example is like this:
scala> def foo(code: => Int) {
| println(code)
| }
foo: (code: => Int)Unit
scala> val bar: () => Int = () => 1
bar: () => Int = <function0>
scala> foo(bar())
1
scala> val bar1: Int => Int = myInt => 2
bar1: Int => Int = <function1>
scala> foo(bar1(2))
2
Could anyone can explain it?
The x: => R in the function definition doesn't stand for function without parameters which returns R, but it means an expression which, when evaluated, returns a value of type R without specifying anything else about the expression itself.
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)