I'm given a list lis
of type List[(Char,Int)]
and need to sort it by chars, but I want do do this using sortWith
function. One way to do this is using:
val newlis = lis.sortWith({case ((a,b),(c,d)) => a<c })
But when I wrote auxilary function:
def aux2(term: ((Char, Int),(Char, Int)) ): Boolean = term match {
case ((a,b),(c,d)) => a<c
case _ => false
}
lis.sortWith(aux2)
I get type mismatch. Why is that?
There is a difference between
def f(a: A, b: B): C
and
def f(ab: (A, B)): C
When lifted and desugared, the first one becomes a Function2[A, B, C]
, while the second one becomes Function[(A, B), C]
. While essentially the same (isomorphic), these two types must be used with a slightly different syntax.
Here is a slightly more complex example with (Char, Int)
instead of A
and B
:
def g1(abcd: ((Char, Int), (Char, Int))): Boolean = abcd._1._2 < abcd._2._2
val g1Fun: (((Char, Int), (Char, Int))) => Boolean = g1
// ^^^ ^
// || \ second component of tuple: (Char, Int)
// || first component of tuple: (Char, Int)
// | \
// | single argument of type ((Char, Int),(Char, Int))
// \
// argument list of `g1Fun`, accepts *one* argument
def g2(ab: (Char, Int), cd: (Char, Int)): Boolean = ab._2 < cd._2
val g2Fun: ((Char, Int), (Char, Int)) => Boolean = g2
// ^^ ^
// || second argument of type (Char, Int)
// | \
// | first argument of type (Char, Int)
// \
// argument list of `g2Fun`, needs *two* arguments
The function lt
in sortWith
behaves like the second function g2Fun
, whereas the function aux2
that you have written is more like the g1Fun
.
So, to fix your code, you have to define aux2
as a binary operation:
val lis: List[(Char,Int)] = List(('a', 34), ('b', 42))
println(lis.sortWith({case ((a,b),(c,d)) => a < c }))
def aux2(
firstTerm: (Char, Int),
secondTerm: (Char, Int)
): Boolean = (firstTerm, secondTerm) match {
case ((a,b), (c,d)) => a < c
case _ => false
}
println(lis.sortWith(aux2))
To make it work with the same arity of f
as you have written, the sortWith
would have to accept a slightly different sort of functions.
Consider this:
def watchTheArity(f: ((Int, Int)) => Int): Int = {
f((4, 5))
}
See the weird double parens wrapping the (Int, Int)
part?
This means: "I expect an f
that takes a single tuple as argument".
Therefore, this works:
def f(ab: (Int, Int)): Int = ab._1 + ab._2
println(watchTheArity(f))
However, if it were defined as
def watchTheArity2(f: (Int, Int) => Int): Int = {
f(4, 5)
}
then you would need an f
that takes two arguments.
Edit notice Added Ascii-art explanation of parentheses.