redundant parameter type info in partially applied function definition - scala

def foo(num:Int, str:String):Int = 1
val bar = foo(3, _) // compiler complains "missing parameter type for expanded function ((x$1) => test(3, x$1))"
val baz = foo(3, _:String) // compiles fine
Why do I have to explicitly specify the type of _ when it looks inferrable from the context?
EDIT: Renamed to avoid name collision following David Soergel's suggest.

First of all, to avoid confusion between "def test" and "val test", let's write:
def foo(num:Int, str:String):Int = 1
val bar = foo(3, _) // compiler complains "missing parameter type for expanded function ((x$1) => foo(3, x$1))"
val baz = foo(3, _:String) // compiles fine
What's inferrable from context is only that the argument to bar must somehow be convertible to a String. That could be due to inheritance (if instead of String you use some non-final type there), or due to an implicit conversion.
Basically the potential for implicits means that the argument to bar could be just about any type at all, so the code as written is indeed underspecified. I don't know whether the compiler actually checks whether there are any appropriate implicit conversions in scope before issuing the "missing type" error, but I would guess not. (In the case of String there are likely to be a bunch present, anyway). It would be brittle and confusing if the signature of baz changed as a result of importing a new implicit that could produce a String.

I think David Soergel's explanation is essentially correct: if type T has an implicit conversion to String then val bar = foo(3, _:T) is valid, giving a function of type T => Int, which is unrelated to String => Int.
Why the compiler doesn't make a sensible assumption (in the absence of explicit typing) that the type is in fact the same as in the method (which is the essence of your question), I don't know - I can only guess it's because it would complicate the language spec.
Where no types are specified, i.e. val bar = foo(_, _), it seems the compiler interprets it as simple eta-conversion, the same as val bar = foo _, which does give a String => Int.
My preferred idiom would be to give the function type on the left hand side, which has the benefit of allowing you to easily see bar's type:
val bar: String => Int = foo(3, _)
If you're allergic to re-typing the word String, you could write
val bar = (foo _).curried(3)

Related

What is the Unit Type Behavior in Scala

Why does this code works:
val f: String => Unit = {(_:String) => 2}
//or more succinctly
val f: String => Unit = _ => 2
Clearly the body of my function return an int. However the type expected is Unit
But if i do
implicitly[String <:< Unit]
//Cannot prove that String <:< Unit.
Hence i am a bit confused as to how the cast is happening ? Why is it even allowed in the first place
This is called Value Discarding, see 6.26.1 Value Conversions, sub-section Value Discarding of the Scala Language Specification:
If 𝑒 has some value type and the expected type is Unit, 𝑒 is converted to the expected type by embedding it in the term { 𝑒; () }.
In other words, your code is compiled as-if you had written
val f: String => Unit = {(_:String) => { 2; () }}
//or more succinctly
val f: String => Unit = _ => { 2; () }
I guess the intention behind this feature is familiarity for programmers coming from imperative programming languages, where it is often possible to discard values.
E.g. in C, it is legal to write
printf("Hello");
and discard the return value, even though printf returns an int. This goes together with the idea of expression statements and statement expressions that many imperative programming languages have.
In Scala any type A can be transformed into type Unit. It's not subtyping, it's transforming. Like type A means some possible side effect plus returning A while Unit means we disregard return value but keep the side effect.

Error in lifting method to function

I have a method that with the implicit parameter. i get a error when i convert it to function in 2 case :
1:
def action(implicit i:Int) = i + " in action"
val f = action _
then i get a StackOverflowError.
2:
def action(implicit i:Int) = i + " in action"
val f = action(_)
then i get a error: missing parameter type
I must write like this :
val f = (i:Int) => action(i)
that's ok. And if the parameter of 'action' is not the implicit , all case are right. So how to explain , and what i miss ?
If you specify a parameter to a function to be implicit, you are inviting the compiler to supply the value of that parameter for you. So how does the compiler find those values? It looks for values of the same type (Int in your case) that have been declared as implicit values in a variety of scopes.
(For simplicity, I'll just use a local scope in this example, but you might want to read up on this topic. Programming in Scala, 3rd Ed is a good first step.)
Note that the names of the implicit values are ignored and have no bearing on proceedings, the compiler only looks at the types of implicit values. If multiple implicit values with the required type are found in the same scope, then the compiler will complain about ambiguous implicit values.
For example, the following provides a function with an implicit parameter and a default value for that parameter within the current scope:
def greetPerson(name: String)(implicit greeting: String) = s"$greeting $name!"
implicit val defaultGreeting = "Hello" // Implicit value to be used for greeting argument.
val y = greetPerson("Bob") // Equivalent to greetPerson("Bob")(defaultGreeting).
val z = greetPerson("Fred")("Hi")
Note that y is just a String value of "Hello Bob!", and z is a string with the value "Hi Fred!"; neither of them are functions.
Also note that greetPerson is a curried function. This is because implicit parameters cannot be mixed with regular, non-implicit parameters in the same parameter list.
In general, it's bad practice to use common types (Int, Boolean, String, etc.) as values for implicit parameters. In a big program, there might be a lot of different implicit values in your scope, and you might pick up an unexpected value. For that reason, it's standard practice to wrap such values in a case class instead.
If you're trying to create a value that supplies some of the arguments of another function (that is, a partially applied function), then that would look something like this:
def greetPerson(greeting: String, name: String) = s"$greeting $name!"
val sayHello = greetPerson("Hello", _: String)
val y = sayHello("Bob") // "Hello Bob!"
val sayHi = greetPerson("Hi", _: String)
val z = sayHi("Fred") // "Hi Fred!"
In both cases, we're creating partially applied functions (sayHi and sayHello) that call greetPerson with the greeting parameter specified, but which allow us to specify the name parameter. Both sayHello and sayHi are still only values, but their values are partially applied functions rather than constants.
Depending upon your circumstances, I think the latter case may suit you better...
I would also read up on how the underscore character (_) is used in Scala. In a partially applied function declaration, it corresponds to the arguments that will be provided later. But it has a lot of other uses too. I think there's no alternative to reading up on Scala and learning how and when to use them.

Removing ambiguity of overloaded method definition

The compiler is getting confused by an overloaded method definiton and I cannot find a way to clarify my intention sufficiently.
I have the following code:
val part: (QueryParams) => List[ResultMap] = (partOf.find _).andThen(makeMap)
The find method is overloaded:
def find(params: QueryParams): List[U] = ...
def find(params: QueryParams, flattener: U => T): List[T] = ...
The code was working fine as long as there was a single definiton of find. Since I had to add the second find definiton with 2 params, the compiler is generating this error:
Error:(15, 31) ambiguous reference to overloaded definition,
both method find in trait DataFetcher of type (params: ...QueryParams)List[...Parser]
and method find in trait DataFetcher of type (params: ...QueryParams, flattener: ...Parser => ...ResultTuple)List[...ResultTuple]
match expected type ?
val part: Fetcher = (partOf.find _).andThen(makeMap)
^
IMHO there is no ambiguity. The type of part is defined to accept one argument of type QueryParams. There is only one method accepting a single QueryParams. U and T are different types and makeMap expects a List[U] There are no implicits, default values or varargs involved.
Is there a way to further clarify my intention to the compiler?
EDIT: one way to remove the ambiguity is to introduce an intermediary value, clarifying the expected type of the eta expansion:
val find: (QueryParams) => List[ResultTuple] = partOf.find _
val part: (QueryParams) => List[ResultMap] = find andThen makeMap
But since makeMap is only accepting List[ResultTuple] I stil dont get the reason for the supposed ambiguity and would prefer not to introduce the extra value. Any clarification?
First, it is important to understand that the trailing underscore is a deliberate design decision to prevent programmer mistakes. The only exception is when the type is explicitly declared.
Here is an example illustrating this point.
object A {
def add(a: Int)(b:Int): Int = a + b
val x: Int => Int = add(5) // compiles fine
val y = add(5) // produces a compiler error
}
The same applies to your question. Because you do not specify the intermediate type, when you write find _, should the compiler infer the type to be QueryParams => List[ResultTuple] (as you may expect) or should it be (QueryParams, U => T) => List[ResultTuple]? Note that the trailing underscore does not stand for a single argument, it just lifts the method to a function. When the type if declared, you can drop the trailing underscore and write find where you would have written find _.
I see from your edit that you found out that an intermediate value with a declared type works. Another (slightly clunky) way to clarify your intent is the following.
val part: (QueryParams) => List[ResultMap] = (x => partOf.find(x)).andThen(makeMap)

Why does Scala require partial application of curried functions when assigning to a val?

In Scala, why is it that a curried function can easily be passed directly to other functions, but when assigning it to a val one needs to also partially apply it with _? For example, given the two functions:
def curried(a: Int)(b: Int) = a + b
def test(a: Int, f: Int => Int) = f(a)
I can easily pass curried to test with:
test(5, curried(5))
and everything is happy. However if I simply call curried(5) I get an error:
scala> curried(5)
<console>:9: error: missing arguments for method curried;
follow this method with `_' if you want to treat it as a partially applied function
curried(5)
If I change the call to include type information however, it works:
val 'curried: Int => Int = curried(5)
Can anyone explain the rational behind the inconsistency, surely the Scala compiler can infer that the function is Int => Int given the type definition on the original method?
The problem is not inferring the type, the problem is inferring your intent. Did you make a mistake, or did you intentionally curry the function?
Alas, the trailing underscore syntax is the formal syntax, and omitting it is syntactical sugar.
The underscore isn't always needed. From http://docs.scala-lang.org/cheatsheets/
val zscore = (mean:R, sd:R) => (x:R) => (x-mean)/sd
currying, obvious syntax.
def zscore(mean:R, sd:R) = (x:R) => (x-mean)/sd
currying, obvious syntax
def zscore(mean:R, sd:R)(x:R) = (x-mean)/sd
currying, sugar syntax. but then:
val normer = zscore(7, 0.4) _
need trailing underscore to get the partial, only for the sugar version.

First parameter as default in Scala

Is there another way of making this work?
def b(first:String="hello",second:String) = println("first:"+first+" second:"+second)
b(second="geo")
If I call the method with just:
b("geo")
I get:
<console>:7: error: not enough arguments for method b: (first: String,second: String)Unit.
Unspecified value parameter second.
b("geo")
Here is one of the possible ways: you can use several argument lists and currying:
scala> def b(first:String="hello")(second:String) = println("first:"+first+" second:"+second)
b: (first: String)(second: String)Unit
scala> b()("Scala")
first:hello second:Scala
scala> val c = b() _
c: (String) => Unit = <function1>
scala> c("Scala")
first:hello second:Scala
See scala language specifications 6.6.1 (http://www.scala-lang.org/docu/files/ScalaReference.pdf):
"The named arguments form a suffix of the argument list e1, ..., em, i.e. no positional argument follows a named one."
Providing a single string parameter (without naming it) is too ambiguous for the compiler. Probably you meant the value for the non-default parameter, but... maybe not. So the compiler wants you to be more specific.
Generally you put all your default parameters at the end of the method signature (if you did in this case, b("geo") would work) so that they can be left out less ambiguously.