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.
Related
I would like to arrive to a syntax as productive as Haskell's desort = (reverse . sort) in Scala... Here is my attempt:
implicit class Composition[A,B,C](val g: A => B) {
def o(f: B => C): A => C = { a:A => f(g(a))}
}
val fg = cos _ o sin
Is there any way we can get rid of the _in the declaration of gf?
For functions yes, but for methods, no. Your problem is that you're trying to use a method for g, and not a function. For functions, there is already a method for this called andThen:
val f: Int => Int = _ + 1
val g: Int => String = _.toString
scala> val fg = f andThen g
fg: Int => String = <function1>
scala> fg(2)
res3: String = 3
Your own implicit class will work as well (though I haven't looked at the exact semantics you desire), using functions like f and g, as I've defined them. It will even work for a function and a method (in that order).
def a(i: Int): Int = i + 1
def b(i: Int): String = i.toString
scala> f andThen a
res4: Int => Int = <function1>
However, a andThen b does not work as-is, because a is a method, which you cannot call andThen on. In order to use andThen, a needs to be converted to a function, which will not happen automatically, because a function isn't necessarily expected. a _ andThen b eta-expands a into a function, in which has a method called andThen, and can be provided an argument of b (a method), because the compiler will implicitly convert b to a function, since a function is the only thing that is expected as an argument of andThen. Function isn't the only type with a method called andThen, so the compiler can't expect one 100% of the time to make the conversion from method to function for a.
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(_).
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've been using scala for a while now and I thought I was really starting to understand everything (well, most things...), but I found myself confused by a number of the method definitions in the Map class. I know how foldLeft, etc work, but what I'm confused about is the type parameters used in the Map functions. Let's use foldLeft as an example:
foldLeft [B] (z: B)(op: (B, (A, B)) ⇒ B) : B
The definition for the Map trait itself takes two type parameters 'A' and 'B' (e.g. Map[A,+B]). From what I can tell, when you define a type parameter for a method using the same name as one of the type parameters for the class/trait, it overrides the class/trait value. Take this definition of Foo as an example:
class Foo[A : Manifest, B : Manifest] {
def isAString() = manifest[A] == manifest[String]
def isAInt() = manifest[A] == manifest[Int]
def isBString() = manifest[B] == manifest[String]
def isBInt() = manifest[B] == manifest[Int]
def nowIsBString[B : Manifest] = manifest[B] == manifest[String]
}
scala> val f = new Foo[String,Int]
f: Foo[String,Int] = Foo#7bacb41
scala> f.isAString
res290: Boolean = true
scala> f.isAInt
res291: Boolean = false
scala> f.isBString
res292: Boolean = false
scala> f.isBInt
res293: Boolean = true
scala> f.nowIsBString[String]
res294: Boolean = true
scala> f.nowIsBString[Int]
res295: Boolean = false
So in the foldLeft definition, 'B' comes from the method definition and 'A' comes from the trait definition. For example:
val xm = Map("test" -> 1, "test2" -> 2)
scala> val foldFn = (z: Int, kv: (String, Int)) => z + kv._2
foldFn: (Int, (String, Int)) => Int = <function2>
scala> m.foldLeft(0)(foldFn)
res298: Int = 3
This is as expected as 'B' for the function matches 'B' for the trait, but what if I change the 'B' type for the function to String instead of Int:
scala> val foldFn = (z: String, kv: (String, String)) => z + kv._2
foldFn: (String, (String, String)) => java.lang.String = <function2>
scala> m.foldLeft("")(foldFn)
<console>:19: error: type mismatch;
found : (String, (String, String)) => java.lang.String
required: (java.lang.String, (java.lang.String, Int)) => java.lang.String
m.foldLeft("")(foldFn)
So let's change the kv parameter to (String, Int):
scala> val foldFn = (z: String, kv: (String, Int)) => z + kv._2
foldFn: (String, (String, Int)) => java.lang.String = <function2>
scala> m.foldLeft("")(foldFn)
res299: java.lang.String = 12
Unlike my Foo example, in this case the Map's 'B' value is taking precedence over the functions definition, but only for the kv parameter. What I would have expected is to see a foldLeft defined as follows:
foldLeft[C] (z: C)(op: (C, (A, B)) => C): C
That would be more clear to me, but it is not defined this way. So does anyone know the rules for when a methods parameter will override a trait/class parameter and when it will not?
Scala is the same as Java in this respect, and the following from the "Names" chapter of the Java specification applies:
A declaration d of a type named n shadows the declarations of any
other types named n that are in scope at the point where d occurs
throughout the scope of d.
So the type parameter for a method will always shadow a class or trait type parameter with the same name. Your Foo example demonstrates this fact.
The apparent counterexample you're seeing in the case of Map's foldLeft is just an unpleasant artifact of the current version of Scaladoc, as is pointed out in the answers to the question you've linked. foldLeft isn't defined in the Map trait, but in TraversableOnce, where there isn't a trait type parameter named B at all.
In general shadowing the type parameter of a trait or class in a method is a really bad idea, of course.
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