Mapping a Scala function with an optional parameter - scala

I'm having trouble mapping a function that takes an optional parameter. I get the same type error as I would if the parameter were not optional. Here's a simple illustration:
scala> def multiple(m: Int, n: Int = 2) = m * n
multiple: (m: Int,n: Int)Int
scala> multiple(5)
res0: Int = 10
scala> multiple(5, 7)
res1: Int = 35
scala> (1 to 10).map(multiple)
<console>:7: error: type mismatch;
found : (Int, Int) => Int
required: (Int) => ?
(1 to 10).map(multiple)
Here's one way to make it work, but it requires repeating the default argument, which is a maintenance nightmare:
scala> (1 to 5).map { n => multiple(n, 2) }
res6: scala.collection.immutable.IndexedSeq[Int] = Vector(2, 4, 6, 8, 10)
Is there a better way to do it? More generally, why does a function with an optional parameter seem to have the same type as it would if the parameter was not optional? What is the actual type of multiple?

This seems to work:
(1 to 10).map(multiple(_))
//res0: scala.collection.immutable.IndexedSeq[Int] = Vector(2, 4, 6, 8, 10, 12, 14, 16, 18, 20)

When used in a situation expecting a function, Scala will "lift" a method to a FunctionN[T1,...,R].
In this situation, because multiple takes 2 parameters, it is lifted effectively as:
(1 to 10).map(new Function2[Int,Int,Int]{ def apply(v1: Int, v2: Int) = multiple(v1, v2) })
Even though the original method has a default argument, FunctionN objects do not. The type error should now be clear here. When multiple(_) is used, this is a call to multiple with a single argument with the second defaulted and so is treated like:
(1 to 10).map(new Function1[Int,Int]{ def apply(v1: Int) = multiple(v1) })
This type checks ok as others have shown.
Note that (multiple _ ) is not the same as multiple(_). The former represents multiple with all arguments wild carded and so is a Function2, whereas the latter is applying multiple to a single wild card argument, causing the other argument to be defaulted at that point, and so is a Function1.
Defaults are implemented at compile time by introducing a new method which returns the default value. Where the defaulted method is called, if arguments are missing, the compiler will add the necessary calls to the extra methods for the default parameters before adding the call to the method itself. This means that the method itself is compiled to code which itself has no knowledge of default parameters. To see this, compile the following sample class:
class Defaults {
def m(a: Int, b: Int = 3) = a * b
def a = m(1)
def b = m(1, 2)
}
then run: javap -c Defaults

For being able to write
scala> (1 to 10).map(multiple)
you can pass a partially applied function
def multiple(m: Int, n: Int) = m * n
val mul2 = multiple(_: Int, 2)
(1 to 10) map mul2

Here's one way to make it work, but it
requires repeating the default
argument, which is a maintenance
nightmare:
Btw this works too:
scala> (1 to 5).map { n => multiple(n) }
res0: scala.collection.immutable.IndexedSeq[Int] = Vector(2, 4, 6, 8, 10)
So you don't need to repeat the default argument either ;) [Scala 2.9.0.RC1]

Related

Scala type annotations on right side?

In scala if I have a declaration such as this:
val i: Float = 5
Is this the same like in this line:
val i = 5: Float
?
Recently I encountered an expression with such type annotation on the right side and I wonder what its usage is as I could not find it in the specs.
This is called type ascription and it's meant to disambiguate types when several options might be available.
A typical example is a fold:
val l = 1 to 5
val stringyfied = l.foldLeft(Nil)((list, elem) => elem.toString :: list)
What is the type of Nil in that case? If you try that example, the compile will bark with an error:
error: type mismatch;
found : List[String]
required: scala.collection.immutable.Nil.type
We can make the specific type known to the compiler by using type ascription:
val stringyfied = l.foldLeft(Nil:List[String])((list, elem) => elem.toString :: list)
// stringyfied: List[String] = List(5, 4, 3, 2, 1)
Another common use is to view a collection as a vararg as in:
def varargs(a:Int*) = a.sum
// common use:
varargs(1,2,3,4,5) //15
// now we have a collection of elements:
val intlist = 1 to 5
// we cannot call varagrs with a list
varargs(intlist)
> found : List[Int]
> required: Int
// then using type ascription:
varargs(intlist: _*)
To my knowledge, there's not much specific documentation about type ascription other than the specification of the algebra of expressions SLS#Chapter6
This syntax is used to assign types to expressions (while val i: Float = 5 assigns a type to a term). It can make a difference when you do it with a part of a bigger expression.
scala> implicit class WeirdFloat(f: Float) {
| def +(ff: Float) = new WeirdFloat(f + ff * 2)
| override def toString = s"$f"
| }
defined class WeirdFloat
scala> val i: WeirdFloat = 5 + 7
i: WeirdFloat = 12.0
scala> val i = (5: WeirdFloat) + 7
i: WeirdFloat = 19.0
I believe the only difference is that the type of i is inferred (by the compiler) from the value in the second example, whereas in the first you are being explicit about the type of i.
The stye guidelines encourage the use of type of inference wherever possible. However, it also mentions that the syntax whereby you follow the value with the type is the approach when you are using ascription - a compile time upcast.
scala> val s = "Jane"
s: String = Jane
scala> val p = s: Object
p: Object = Jane

Scala "type" alias confusion

I am working on Coursera Assignment and in Week 2. This week assignment is not tough but very confusing.
I wrote below code and it works fine
def union(s:Set[Int], t:Set[Int]):Set[Int] = s union t
But if I use type to create alias of Set and rewrite above as
type Set = Int => Boolean
def union(s:Set, t:Set):Set = s union t
Now I get error for union is not a member of Set
def union(s:Set[Int], t:Set[Int]):Set[Int] = s union t
This works because Set[T] defines a function named union, which is called in the above code.
type Set = Int => Boolean
def union(s:Set, t:Set):Set = s union t
This doesn't work because functions don't have a method named union.
From what I can remember way back when I did that course, you are not supposed to use any standard library types to build your solutions. So you are not supposed to use Set[T] from the standard library. In the collection library, union is defined and works as expected.
However, the course requires you to define your own type for Set and I believe it is Int => Boolean.
What you actually need is a function like this:
type Set = Int => Boolean
def union (s1 : Set, s2 : Set) : Set = (x:Int) => s1(x) || s2(x)
That is, you need to define a lambda.
You already have union function present in scala. You can verify in repl by doing:
> val x: Set[Int] = Set(1,2,3)
> x.union(Set(3, 4, 5))
res0: scala.collection.immutable.Set[Int] = Set(5, 1, 2, 3, 4)
Let's say you want to define your own function to do exactly the same thing, you can write:
def myunion[T](x: Set[T], y: Set[T]): Set[T] = x.union(y)
This is generic method(just like in set) and you can call it:
> myunion(Set(1, 2, 3), Set(3, 4, 5))
//but it also works for other types:
> myunion(Set('a', 'b', 'c'), Set('c', 'd', 'e'))
Aliasing type is done with slightly different syntax:
type SetInt = Set[Int]
type SetChar = Set[Char]
When you do type Set = Int => Boolean, you create Function1 type.
You can check it by yourself in scala repl;
scala> type Set = Int => Boolean
defined type alias Set
scala> val test: Set = i => true
test: Set = <function1>
As you see in Function1[-T1, +R] trait extends AnyRef which doesn't have union method but Set has it.

missing parameter type for `_`

I'm trying to sort a list by how close the entries of a list are to num.
I decided to try use sortWith, but the following snippet:
list.sortWith(math.abs(_ - num) < math.abs(_ - num))
failed with missing parameter type for _ in scala.
list is of type List[Int].
Following the other threads, I know that _ is somehow type ambiguous, but I'm not sure why, (and why the following snippet is not type ambiguous):
scala> val sortedDudes = dudes.sortWith(_.name < _.name)
sortedDudes: Array[Person] = Array(Al, Paul, Tyler)
(Source)
def foo = {
val num = 2
val list: List[Int] = List(1, 2)
list.sortWith((a, b) => math.abs(a - num) < math.abs(b - num))
}
work perfectly. It's because scala trying get _ from math.abs, not sortWith
In Scala, _ can be used in a variety of different situations to mean different things. The answers on this question should help clarify a few of them.
Going back to the question, it seems the OP is trying to use _ for parameter replacement. Consider the following example
List(1,2,5,7).filter(_ > 4)
Here filter takes a function of type A => Unit, so the above is shorthand for
List(1,2,5,7).filter(x => x > 4)
The underscore can stand for more than one parameter, but it must be used to refer to each parameter exactly once. This is why the sortedDudes snippet in the OP works. Therefore the following is legal.
List(1,2,5,7).reduce(_ + _)
which is shorthand for
List(1,2,5,7).reduce((a,b) => a + b)
I think the problem with the original snippet is that the compiler cannot unambiguously parse it into something of type (A, A) => Boolean as required by the sortWith method. We can give the compiler a little help as follows.
scala> def op(int: Int, num: Int) = math.abs(int - num)
op: (int: Int, num: Int)Int
scala> List(1,7,5,10).sortWith(op(_, 5) < op(_, 5))
res0: List[Int] = List(5, 7, 1, 10)

Scala: Is it possible to get partially applied function from leftfold?

I'm currently learning Scala, and I just wondered at fold-left.
Since fold-left is curried, you should be able to get a partially applied function(PAF) with a first parameter as below.
(0 /: List(1, 2, 3)) _
But actually, I've got an error.
<console>:8: error: missing arguments for method /: in trait TraversableOnce;
follow this method with `_' if you want to treat it as a partially applied function
Then I tried same thing by fold-right such as below
(List(1, 2, 3) :\ 0) _
In this way, it went correctly, and I could get a PAF such as ((Int, Int) => Int) => Int
I know I can get a PAF by using foldLeft method, but I wonder whether it is possible to express it with '/:' or not.
The underscore syntax does not work well with right-associative methods that take multiple parameter lists. Here are the options I see:
Declare a variable type:
val x: ((Int, Int) => Int) => Int = 0 /: List(1, 2, 3)
Similarly, use type ascription:
val x = (0 /: List(1,2,3)) : ((Int, Int) => Int) => Int
Use the postfix notation:
val x = List(1,2,3)./:(0) _
Use the foldLeft synonym:
val x = List(1,2,3).foldLeft(0) _
I played around with it, and couldn't find a configuration that works.
There's always the more explicit:
val f = List(1,2,3,4,5).foldLeft(0)_
Which is arguably neater. I'll keep poking around though.
Edit:
There's this:
val f2 = (0 /: List(1,2,3,4,5))(_: (Int,Int) => Int)
val x = f2(_+_)
But that's getting pretty ugly. Without the type annotation, it complains. That's the best I could do though.

What's the advantage of using multiple lists of function parameters?

scala> def a(i:Int)(j:Int) = i * j
a: (i: Int)(j: Int)Int
scala> def b(i:Int, j:Int) = i * j
b: (i: Int, j: Int)Int
The two definitions are very similar, and they (appear to me) do the same thing.
Apart from defining a function which receives implicit parameters or a code block as parameter, is there any reason to use the first definition style?
This is the list I have compiled over the time:
1) Type resolution across multiple argument lists
class ResourceManager {
type Resource
def open: Resource = ???
}
class ResourceManagerTest {
// Does not compile: def test1(rm: ResourceManager, r: rm.Resource) = ???
// Compiles: This way the type can be resolved
def test2(rm: ResourceManager)(r: rm.Resource) = ???
}
2) Type inference where earlier arguments can "lock down" type parameters for later arguments (thanks to Myserious Dan)
def foo1[A](x: A, f: A => Int) = ???
def foo2[A](x: A)(f: A => Int) = ???
def foo1foo2Demo() {
// This will always demand a type annotation on any anonymous function
// you pass in:
foo1(1, (i: Int) => i * i)
// Does not compile: foo1(1, i => i * i)
// Type not required
foo2(2)(i => i * i)
}
3) Syntax-like language extensions
object MultipleArgumentListsDemo {
// This style of function definition allows syntax-like language extensions
#tailrec
def myWhile(conditional: => Boolean)(f: => Unit) {
if (conditional) {
f
myWhile(conditional)(f)
}
}
def myWhileDemo() {
var count = 0
myWhile(count < 5) {
count += 1
println(count)
}
}
4) Having both implicit and non implicit arguments, as implicit is a modifier for a whole argument list:
def f[A](x: A)(implicit mf: Manifest[A]) {
}
5) A parameter's value from one parameter list can be used to compute a default value in another parameter list, but not in the same one.
def g(x: Int)(y: Int = x * 2) = {
x + y
}
6) Multiple repeated argument lists ("varargs")
def h(as: Int*)(bs: Int*)(cs: Int*) = as.sum * bs.sum * cs.sum
7) Partial application
def i() {
val foop = h(1, 2, 3)(4, 5, 6, 7, 9) _
println(foop(Seq(10, 11)))
}
As I have not tracked my sources while I was compiling that list over the time: It's possible that some or all examples are copied from elsewhere (other questions on SO), so please drop a note, and I will add the reference as to where it came from.
The main reason for "currying" functions in this manner is to enable partial application:
scala> val c = a(5) _
c: Int => Int = <function1>
Here c is a function that takes a single int and returns the result of multiplying that int with 5. It may be that you would set up c in one method, and pass it into another method that expects a function taking one Int parameter. A bit trivial in this case, but very flexible for a range of uses.
Additional to support currying, it also helps with type inference: Sometimes the compiler can't infer the correct type if everything is in one argument list, but if you split off the part that depends on the binding of the other arguments, it works. A typical example is foldLeft: Try to implement it with one argument list, and then in some cases the compiler needs type annotations.