I'm beginner in scala.
Anonymous function syntax is clear for me:
(a: Int) => Int,
without parentheses: a: Int => Int - compile error.
But can somebody explain me purpose of this syntax?
{a: Int => Int}
Just another form of anonymous function?
I don't think it is clear to you.
(a: Int) => Int
this line is not something that someone would actually type. It creates an anonymous function that takes an Int named here a and returns an object Int that is of type Int.type and this is companion object of Int class.
scala> (a: Int) => Int
res0: Int => Int.type = <function1>
This is exactly the same thing, just wrapped in useless block that will evaluate to the only expression inside it.
{a: Int => Int}
To do things properly, to define anonymous function say
val fun = (a: Int) => a + 5
i.e. put some expression that should be evaluated.
You can also annotate the type of this val
val fun: Int => Int = _ + 5
To define the type of function, you say for example Int => Int
def apply5(f: Int => Int) = f(5)
It seems like you mixed those two concepts (definition of anonymous function and type of function).
Having defined both you can say
apply5(fun)
Which will have result 10
I think there is no notable difference between {a: Int => a + 5} and (a: Int) => a + 5. Actually both are quite common. For example look at defining an action in Play (type of request is annotated just to apply to the example, it is not needed)
Action { request: Request[AnyContent] =>
// some more code
Ok("")
}
It is an anonymous function, that takes a single argument a of type Int, discards it, and returns a scala object scala.Int representing the type Int.
You can answer questions like this yourself fairly easily with the help of scala repl:
scala> val f = { a: Int => Int }
f: Int => Int.type = <function1>
scala> f(1)
res210: Int.type = object scala.Int
Related
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
While trying to grasp Scala implicits, I ran into this type inference problem:
object Demo extends App {
def demo(f: (Int, Int) => Int) = ???
demo((a: Int) => 42)
demo((a) => 42) // <-- any tricks to make this compile?
implicit def f1Tof2(f: Int => Int): (Int, Int) => Int =
(a: Int, b: Int) => f.apply(a)
}
What's the reason behind the compiler's inability to infer the type correctly? Any tricks to make it work?
This isn't possible. When you call demo((a, b) => a + b) (for example), the compiler is already expecting an (Int, Int) => Int, so it will infer (a, b) => a + b as (Int, Int) => Int, since it has the correct shape.
However, when you call demo(a => 42), the compiler sees a Function1[?, Int] as the argument, with no indication as to what the parameter type is. Since demo expects a Function2, the only way this can compile is if the compiler can find an implicit conversion from the passed argument type to (Int, Int) => Int. But it can't, because it doesn't know the type it's converting from. It cannot just assume it will a Int => Int.
There are only two ways to make this work.
1.) Explicitly declare the parameter type of the anonymous function, like you have done already. This is the only way the implicit conversion can be applied.
demo((a: Int) => 42)
2.) Provide an overload for demo that accepts a Int => Int.
def demo(f: (Int, Int) => Int): Int = f(1, 2)
def demo(f: Int => Int): Int = demo((a, b) => f(a))
scala> demo(a => 42)
res3: Int = 42
I want below code to be type-checked.
val f: Int => String = x => "a"
val g: (=> Int) => String = x => "b"
def t(h: ???): String = h(42)
t(f)
t(g)
What should be put in "???"?
I have read this link and tried it.
t[Int => String, (=> Int) => String].common
res4s: reflect.runtime.universe.TypeTag[=> Int with Int => String] = TypeTag[=> Int with Int => String]
So I put "=> Int with Int => String" in the ???, but t(g) does not type-check.
I have tried "(=> Int with Int) => String" but t(f) does not type-check.
So the question is,
What is the meaning of "=> Int with Int => String" and why t(g) does not type-check
What is the meaning of "(=> Int with Int) => String" and why t(f) does not type-check
What should be put in ???
Thanks a lot.
First of all type X => Y i.e. Function1[X,Y] is contravariant on type parameter X so you should search least common subtype, not greatest common supertype of X and =>X
Second - unfortunately there is not such subtype. More over it's very hard to define anything except function using type =>X. Although it's known such definition desugars later to Function0[X] on typecheck level types =>X and ()=>X are not equivalent.
Happily we could define complex relations between types for our needs using typeclasses.
As we could use =>X only in parameter types we could define such a thing:
case class ParamConvertible[X, Y, T](apply: ((Y => T) => X => T))
Which looks and works like some narrow version of contravariant functor
And provide two obvious implementations
implicit def idParamConvertible[X, T] = ParamConvertible((f: X => T) => (x: X) => f(x))
implicit def byNameParamConvertible[X, T] = ParamConvertible((f: (=> X) => T) => (x: X) => f(x))
Now we can generalize your t function as
def t[T](h: T => String)
(implicit conv: ParamConvertible[Int, T, String]): String =
conv.apply(h)(42)
At this point your
t(f)
t(g)
Should compile and run nicely
The problem is that Int => String and (=> Int) => String don't have useful common super type. Int => String is the type of a call-by-value function which takes an Int value as first parameter and returns a String.
In contrast to that (=> Int) => String is a call-by-name function which takes an expression of type Int as the first parameter. Every time you access the call-by-name parameter the expression is evaluated. Thus, it is effectively a zero argument function returning an Int.
What you can do is to convert the call-by-name function into a call-by-value function so that t(h: Int => String): String type checks also with g. You simply have to call t(g(_)).
Let's define f, a function that supports currying :
def f(a: Int)(b: Int) = a + b
This code doesn't compile
def g= f(1)
<console>:10: error: missing arguments for method f;
follow this method with `_' if you want to treat it as a partially applied function
def g= f(1)
I've found these 2 workarounds :
scala> def h = f(1) _
h: Int => Int
scala> def i : Int => Int = f(1)
i: Int => Int
But i don't understand why the inference engine need help in a trivial case like that ?
This is because def f(a: Int)(b: Int) is not a function but a method with multiple parameter lists. Scala doesn't unify both of them to a single concept, thus you have to distinguish between them as well.
To partially apply a method with multiple parameter lists (and therefore implicitly convert this method to a function) you have to add an underscore after the method, as the error message suggests. When you tell the compiler explicitly which signature you want to have, it can also implicitly convert a method to a function (as seen in your second workaround).
If you want to use currying in Scala it's best to create a function from the beginning:
scala> val f = (a: Int) => (b: Int) => a+b
f: Int => (Int => Int) = <function1>
scala> val g = f(1)
g: Int => Int = <function1>
I have a definition of next methods:
def add1(x: Int, y: Int) = x + y
def add2(x: Int)(y: Int) = x + y
the second one is curried version of first one. Then if I want to partially apply second function I have to write val res2 = add2(2) _. Everything is fine. Next I want add1 function to be curried. I write
val curriedAdd = (add1 _).curried
Am I right that curriedAdd is similiar to add2?
But when I try to partially apply curriedAdd in a such way val resCurried = curriedAdd(4) _ I get a compilation error. Then I fix it to
val resCurried = curriedAdd(4)
Why the result of a Functions.curried differs from curried version of add function(from add2)?
Firstly curriedAdd is same as add2 _ and not add2. add2 is just a method.
scala> curriedAdd
res52: Int => (Int => Int) = <function1>
scala> add2 _
res53: Int => (Int => Int) = <function1>
About the second question. I think the below is the reason. Doing
scala> val i = curriedAdd(23)
i: Int => Int = <function1>
scala> i _
res54: () => Int => Int = <function0>
scala> curriedAdd(23) _
<console>:10: error: _ must follow method; cannot follow Int => Int
curriedAdd(23) _
curriedAdd(23) _ does not work. Lets look at scala manual (§6.7)-
The expression e _ is well-formed if e is of method type or if e is a
call-by-name parameter. If e is a method with parameters, e _
represents e converted to a function type by eta expansion (§6.26.5).
If e is a parameterless method or call-by-name parameter of type =>T ,
e _ represents the function of type () => T , which evaluates e when
it is applied to the empty parameterlist ().
Remember it only evaluates if it is a method or call-by-name parameter. In curriedAdd(23) _, it does not evaluate curriedAdd(23) but checks if it is a method or call-by-name. It is not a method nor a call-by-name parameter.
It is not by-name because by-name is the property of variable. Above you get a by-name parameter after evaluating curriedAdd(23) but curriedAdd(23) in itself is not a by-name variable. Hence the error (Ideally the compiler should have coverted it). Note that the below works:
scala> curriedAdd(23)
res80: Int => Int = <function1>
scala> res80 _
res81: () => Int => Int = <function0>
The above works because res80 _, here you are applying _ to a call-by-name parameter and hence does the conversion.
To answer this question, let's take a look at the REPL.
First we define the two functions as you did.
scala> def add1(x: Int, y: Int) = x + y
add1: (x: Int, y: Int)Int
scala> def add2(x: Int)(y: Int) = x + y
add2: (x: Int)(y: Int)Int
We have defined two functions. The first one expects two parameters in one parameterlist. The second one expects two parameters, each one in an own parameterlist. The result type is the same.
Let's move on.
scala> val curriedAdd = (add1 _).curried
curriedAdd: Int => (Int => Int) = <function1>
You just created a partial applied function, that expects one parameter and returns a partial applied function of type Int => Int. This is not as similar to add2 as you expect it to be.
To achieve the same for add2, you would need to call
scala> val curriedAdd2 = add2 _
curriedAdd2: Int => (Int => Int) = <function1>