Simplified, from a more complex program:
scala> type T = (String) => String
defined type alias T
scala> def f(s: String) = s + " (parsed)"
f: (s: String)java.lang.String
scala> f _
res0: (String) => java.lang.String = <function1>
scala> def g(func: T) = func _
<console>:6: error: _ must follow method; cannot follow (String) => String
def g(func: T) = func _
^
I don't really understand why this doesn't work. What is the difference between a method and something in the form of (Type1, Type2 ...) => Type, and what's the right way of getting the function partial from something like that?
In Scala there is a difference between methods and functions. Methods always belong to an object, but functions are objects. A method m can be converted into a function using m _
See Difference between method and function in Scala
scala> def g(func: String => String) = func(_)
g: (func: (String) => String)(String) => String
Parenthesis make all the difference. This is one of the tricky things about the binding of _; it can be used to lift a method to a closure, and it can be used for partial application, but the two usages are not the same!
is this what you're trying to do?
scala> def g(func: T) = func
g: (func: (String) => String)(String) => String
scala> g(f)("test")
res8: String = test (parsed)
I think you're looking for this: http://jim-mcbeath.blogspot.com/2009/05/scala-functions-vs-methods.html
Related
There are some discussions here about this, but I have some specific questions I wasn't able to find an answer for. So, by call-by-name, I mean =>T type, and by 0-arity function I mean () => T
I understand (I think) the conceptual difference, but probably I am missing something as I still have lots of questions:
Why do we have the concept of =>T at all if we could always use () => T?
Is there any syntax/functional limitations of each? For now I found only that => cannnot be used as a class field. Is this the only limitation?
Is the generated code always the same for both?
Should I always prefer =>T? And why?
Is it correct to call =>T a type? It looks for me like it does not have any type representation in scala.
1) It's just more handy to use it, especially inside DSLs:
def printAndGet[T](f: => T) = {
val res = f
println(res + " printed")
res
}
scala> :paste
// Entering paste mode (ctrl-D to finish)
val k = printAndGet {
val a = 5
5 * a
}
// Exiting paste mode, now interpreting.
25 printed
k: Int = 25
2) => T can only be a parameter of method or function. And actually => T and () => T aren't interchangable:
scala> def aaa(f: => String) = f
aaa: (f: => String)String
scala> val a: Function1[() => String, String] = aaa _
<console>:8: error: type mismatch;
found : (=> String) => String
required: (() => String) => String
val a: Function1[() => String, String] = aaa _
^
Thanks to #som-snytt, fоund this one:
scala> object O { def f(i: Int) = i; def f(i: => Int) = i + 1 }
defined object O
scala> O.f(5)
res12: Int = 5
scala> O.f(5: (=> Int))
<console>:1: error: no by-name parameter type allowed here
O.f(5: (=> Int))
^
Even this which should work if it compiles - but it doesn't (scala 2.11.2, 2.11.5 REPL just crashes):
scala> val k: (=> Int) => Int = O.f _
k: (=> Int) => Int = <function1>
scala> k(5) //should be 6
res18: Int = 5 //WTF?
Last one seems like a bug
3) Not exactly, if you want the same, just convert => T into () => T:
scala> def aaa(f: => String) = {f _}
aaa: (f: => String)() => String
Bytecode may also differ. For instance, compiler will more likely inline code from => T without generating lambda for it. So, the key difference is that () => T is actually an object (first class citizen), => T isn't.
4) see 1, but sometimes you may need to ensure that user knows that computation might be delayed - () => T is better then.
5) It's part of a type signature, just look at eta-expansion of:
scala> def aaa(f: => String) = {f}
aaa: (f: => String)String
scala> aaa _ //convert method into a function
res7: (=> String) => String = <function1>
scala> val a: ( => String) => String = aaa _
a: (=> String) => String = <function1>
However scala doesn't recognize it as independent type:
scala> val a: Function1[( => String), String] = aaa _
<console>:1: error: no by-name parameter type allowed here
val a: Function1[( => String), String] = aaa _
^
Update (2018): my prayers were answered in Dotty (Type Lambdas), so the following Q&A is more "Scala 2.x"-related
Just a simple example from Scala:
scala> def f(x: Int) = x
f: (x: Int)Int
scala> (f _)(5)
res0: Int = 5
Let's make it generic:
scala> def f[T](x: T) = x
f: [T](x: T)T
scala> (f _)(5)
<console>:9: error: type mismatch;
found : Int(5)
required: Nothing
(f _)(5)
^
Let's look at eta-expansion of polymorphic method in Scala:
scala> f _
res2: Nothing => Nothing = <function1>
Comparison with Haskell:
Prelude> let f x = x
Prelude> f 5
5
Prelude> f "a"
"a"
Prelude> :t f
f :: t -> t
Haskell did infer correct type [T] => [T] here.
More realistic example?
scala> identity _
res2: Nothing => Nothing = <function1>
Even more realistic:
scala> def f[T](l: List[T]) = l.head
f: [T](l: List[T])T
scala> f _
res3: List[Nothing] => Nothing = <function1>
You can't make alias for identity - have to write your own function. Things like [T,U](t: T, u: U) => t -> u (make tuple) are impossible to use as values. More general - if you want to pass some lambda that rely on generic type (e.g. uses generic function, for example: creates lists, tuples, modify them in some way) - you can't do that.
So, how to solve that problem? Any workaround, solution or reasoning?
P.S. I've used term polymorphic lambda (instead of function) as function is just named lambda
Only methods can be generic on the JVM/Scala, not values. You can make an anonymous instance that implements some interface (and duplicate it for every type-arity you want to work with):
trait ~>[A[_], B[_]] { //exists in scalaz
def apply[T](a: A[T]): B[T]
}
val f = new (List ~> Id) {
def apply[T](a: List[T]) = a.head
}
Or use shapeless' Poly, which supports more complicated type-cases. But yeah, it's a limitation and it requires working around.
P∀scal is a compiler plugin that provides more concise syntax for encoding polymorphic values as objects with a generic method.
The identity function, as a value, has type ∀A. A => A. To translate that into Scala, assume a trait
trait ForAll[F[_]] {
def apply[A]: F[A]
}
Then the identity function has type ForAll[λ[A => A => A]], where I use the kind-projector syntax, or, without kind-projector:
type IdFun[A] = A => A
type PolyId = ForAll[IdFun]
And now comes the P∀scal syntactic sugar:
val id = Λ[Α](a => a) : PolyId
or equivalently
val id = ν[PolyId](a => a)
("ν" is the Greek lowercase letter "Nu", read "new")
These are really just shorthands for
new PolyId {
def apply[A] = a => a
}
Multiple type parameters and parameters of arbitrary kinds are supported by P∀scal, but you need a dedicated variation on the above ForAll trait for each variant.
I really like #Travis Brown 's solution:
import shapeless._
scala> Poly(identity _)
res2: shapeless.PolyDefns.~>[shapeless.Id,shapeless.Id] = fresh$macro$1$2$#797aa352
-
scala> def f[T](x: T) = x
f: [T](x: T)T
scala> Poly(f _)
res3: shapeless.PolyDefns.~>[shapeless.Id,shapeless.Id] = fresh$macro$2$2$#664ea816
-
scala> def f[T](l: List[T]) = l.head
f: [T](l: List[T])T
scala> val ff = Poly(f _)
ff: shapeless.PolyDefns.~>[List,shapeless.Id] = fresh$macro$3$2$#51254c50
scala> ff(List(1,2,3))
res5: shapeless.Id[Int] = 1
scala> ff(List("1","2","3"))
res6: shapeless.Id[String] = 1
Poly constructor (in some cases) will give you eta-expansion into Shapeless2 Poly1 function, which is (more-less) truly generic. However it doesn't work for multi-parameters (even with multi type-parameters), so have to "implement" Poly2 with implicit + at approach (as #som-snytt suggested), something like:
object myF extends Poly2 {
implicit def caseA[T, U] = at[T, U]{ (a, b) => a -> b}
}
scala> myF(1,2)
res15: (Int, Int) = (1,2)
scala> myF("a",2)
res16: (String, Int) = (a,2)
P.S. I would really want to see it as a part of language.
It seems to do this you will need to do a bit type hinting to help the Scala type inference system.
def id[T] : T => T = identity _
So I guess if you try to pass identity as a parameter to a function call and the types of that parameter are generic then there should be no problem.
Let's say I want to create an alias for a method:
def foo = bar(_)
This will warn that
Anonymous function convertible to a method value
And I'm not quite sure what that's supposed to mean, because when I try what I think this might mean:
def foo = bar
I get an error
Missing arguments for method bar(a:A)
Cannot resolve reference bar with such signature.
First, If you want to create an "alias" for method, that's enough:
scala> val foo = bar(_) //val instead of def, still warning from Idea
foo: Int => Int = <function1>
Second, this shoud remove Idea's warning:
scala> val foo = bar _
foo: Int => Int
Actually, it's not just alias - your method becomes converted into a function (eta-expansion). You cant' just specify method (compile-time entity) as compiler will expect parameters - you need to convert it into a function (using underscore) first. Sometimes it's done automatically when compiler expects a function:
scala> val foo: Int => Int = bar
foo: Int => Int = <function1>
So this probably what Idea wants from you. In other cases - you have to use eta-expansion operator (_) explicitly.
P.S/1. def foo = bar(_) (def instead of val) makes no sense as it will return new (but same) function every time, val (or lazy val to be safe from NullPointerException) just returns it once.
P.S/2. The difference between (_) and _ is that first is partially applied function (which does _ eta-expansion automatically), which means that for let's say:
scala> def bar(a: Int, b: Int) = a
bar: (a: Int, b: Int)Int
scala> def foo = bar _
foo: (Int, Int) => Int
scala> def foo = bar(_)
<console>:8: error: missing parameter type for expanded function ((x$1) => bar(x$1))
def foo = bar(_)
^
<console>:8: error: not enough arguments for method bar: (a: Int, b: Int)Int.
Unspecified value parameter b.
def foo = bar(_)
^
scala> def foo = bar(_, _)
foo: (Int, Int) => Int
you have to specify bar(_, _) as there are two arguments.
That's a suggestion from IntelliJ. If you click "More" in the suggestion, you'll see the following (sorry it's graphic, I can't copy the text):
You can either ignore or use bar _ instead of bar(_).
Given two functions:
def f(a: String, b: Int): Int = a.length + b
val g: Int => String = _.toString
why is it that I can compose a partially applied f with g by means of an intermediate assignment:
val f_ = f(_: String, 42)
f_ andThen g
// String => String = <function1>
but not directly:
f(_: String, 42) andThen g
// error: value andThen is not a member of Int
Is this a problem with the type inferencer or somehow expected behavior?
This is just a syntactic error, if you turn on -Xprint:parser option you'll see the difference between your expression and the correct one, i.e: (f(_: String, 42)) andThen g.
Your expression:
((x$1: String) => f((x$1: String), 42).andThen(g))
The correct one:
((x$1: String) => f((x$1: String), 42)).andThen(g)
You can see the difference. It happens because of expansion rule, scalac first normalise syntax to the dot form and then expand it. The same rule applies to this form of function application: func(_) which is expanded to the inner-most braces, I don't remeber where in SLS it's written.
I am trying to define a Map literal with key: String, value: (Any)=>String. I tried the following, but get a syntax error:
def foo(x: Int): String = /...
def bar(x: Boolean): String = /...
val m = Map[String, (Any) => String]("hello" -> foo, "goodbye" -> bar)
Funny that no one actually gave a type that would work. Here's one such:
def foo(x: Int): String = x.toString
def bar(x: Boolean): String = x.toString
val m = Map[String, (Nothing) => String]("hello" -> foo, "goodbye" -> bar)
The reason why it works this way is because Function1 is contra-variant on the input, so (Nothing) => String is a superclass of (Int) => String. It is also co-variant on the output, so (Nothing) => Any would be a superclass to any other Function1.
Of course, you can't use it like that. Without manifests, you can't even uncover what the original type of Function1 is. You could try something like this, though:
def f[T : Manifest](v: T) = v -> manifest[T]
val m = Map[String, ((Nothing) => String, Manifest[_])]("hello" -> f(foo), "goodbye" -> f(bar))
val IntManifest = manifest[Int]
val BooleanManifest = manifest[Boolean]
val StringManifest = manifest[String]
m("hello")._2.typeArguments match {
case List(IntManifest, StringManifest) =>
m("hello")._1.asInstanceOf[(Int) => String](5)
case List(BooleanManifest, StringManifest) =>
m("hello")._1.asInstanceOf[(Boolean) => String](true)
case _ => "Unknown function type"
}
Int => String is not a subclass of Any => String, rather, the contrary. You can't put (replace) an Int => String function when a code expects Any => String, since that code can apply the function with, say, "hi".
#Ben suggestion works, but how is it useful? you can't invoke the function once you get it from the Map.
If you really want to do this, maybe define foo as a partial function:
val foo: PartialFunction[Any, String] = {case i: Int => ....}
Obviously, this will fail at runtime if you pass it a string, but you can always test if the function is ok for use with your parameter by using isDefinedAt. (another alternative may be manifests, but I don't see the value here)
If I let the compiler infer it I seem to get an illegal type:
scala> val m = Map("hello" -> foo _, "goodbye" -> bar _)
m: scala.collection.immutable.Map[java.lang.String,(Boolean with Int) => String] =
Map((hello,<function1>), (goodbye,<function1>))
scala> m("hello")(8)
<console>:9: error: type mismatch;
found : Int(8)
required: Boolean with Int
m("hello")(8)
scala> var q = new Boolean with Int
<console>:5: error: illegal inheritance from final class Boolean
var q = new Boolean with Int
Anyway, what you want is not the type Any but a generic of "any type" which is _:
scala> val mm = Map[String, (_) => String]("hello" -> foo _, "goodbye" -> bar _)
mm: scala.collection.immutable.Map[String,Function1[_, String]] =
Map((hello,<function1>), (goodbye,<function1>))
I just posted a question about how to invoke such functions because I don't actually know.
Trait Function1 is contravariant for parameter, so def foo(x: Int): String is not a (Any) => String. So the following would work:
scala> def baz(x: Any): String = "baz"
baz: (x: Any)String
scala> val m2 = Map[String, (String) => String]("hello" -> baz)
m2: scala.collection.immutable.Map[String,(String) => String] = Map((hello,<function1>))
This is how I did it to fulfill a similar requirement.
object MapToMethods {
private def increment(x: Int): Int = x+1
private def decrement(x: Int): Int = x-1
val m: Map[String, Int => Int] =Map("increment" -> increment, "decrement" ->decrement)
println(m("increment")(2)) //prints 3
println(m("decrement")(3)) //prints 2
}