You're running into two separate problems here. The first is that isSorted
when it is passed to curry
is forced to become monomorphic. The second is that Scala's type inference is failing you here.
This is one of those times where the difference between a function and a method matters in Scala. isSorted
is eta-expanded into a function which in turn is a Scala value, not a method. Scala values are always monomorphic, only methods can be polymorphic. For any method of types (A, B) C
(this is the syntax for a method type and is different from (A, B) => C
which is a function and therefore a value), the default eta-expansion is going to result in the superclass of all functions of that arity, namely (Nothing, Nothing) => Any
. This is responsible for all the Nothing
s you see (you don't have any Any
s because isSorted
is monomorphic in its return value).
You might imagine despite the monomorphic nature of Scala values though, that you could ideally do something like
def first[A, B](x: A, y: B): A = x
curry(first)(5)(6) // This doesn't compile
This is Scala's local type inference biting you. It works on separate parameter lists from left to right first
is the first thing to get a type inferred and as mentioned above, it gets inferred to be (Nothing, Nothing) => Any
. This clashes with Int
s that follow.
As you've realized, one way of getting around this is annotating your polymorphic method that you pass to curry
so that it eta-expands into the correct type. This is almost certainly the way to go.
Another thing you could possibly do (although I'm don't think it'll serve anything except pedagogical purposes) is to curry curry
itself and define it as follows:
def curryTwo[A, B, C](x: A)(y: B)(f: (A, B) => C): C = f(x, y)
On the one hand, the below works now because of the left-to-right type inference.
curryTwo(5)(6)(first) // 5
On the other hand, to use curryTwo
in the scenarios where you'd want to use curry
, you're going to need to need to provide types to Scala's type inference engine anyway.