How do you invoke a Function1[_, String] in Scala? - scala

I answered a question about a map of functions in Defining a Map from String to Function in Scala which led to a Function1[_, String] which I believe is correct as far as the typing question but possibly useless because I don't know how to invoke such a function:
scala> def f(x: Int) = x.toString
f: (x: Int)java.lang.String
scala> f(8)
res0: java.lang.String = 8
scala> val g: Function1[_, String] = f _
g: Function1[_, String] = <function1>
scala> g(8)
<console>:8: error: type mismatch;
found : Int(8)
required: _$1 where type _$1
g(8)
^
scala> val h: Function1[Int, String] = g
<console>:7: error: type mismatch;
found : (_$1) => String where type _$1
required: (Int) => String
val h: Function1[Int, String] = g
Is there any way to use g?

scala> g.asInstanceOf[Any => String](5)
res3: String = 5
It will work because all functions erase to the same thing: Function1[AnyRef, AnyRef]. When you specify it as Any, then passing an AnyVal will auto-box it on call (and it will be auto-unboxed at the method).
However, you do have to pass the correct parameter type. Or else...
scala> g.asInstanceOf[Any => String](true)
java.lang.ClassCastException: java.lang.Boolean cannot be cast to java.lang.Integer

I would say that it's like if you've cast an object of type String as Any, if you want to use a method defined in String you have to cast it back as a String.
You cast the function as a function that takes an argument of an existential type (which is what _ in a type context means), so you can't use it as a function that takes an Int. To use it as a function that takes an Int you have to cast it back.
The same problem exists when pattern matching with collections, or other generic classes:
def firstLength(collection: Any): Int ={
collection match {
// this is how you would have liked to write it
// case list: List[String] => list.head.length
// case map: Map[String, String] => map.values.head.length
// but this is how you have to write it because of type erasure
case list: List[_] => list.asInstanceOf[List[String]].head.length
case map: Map[_, _] => map.asInstanceOf[Map[String, String]].values.head.length
}
}
The type information isn't there, so you can't match on List[String], instead you have to match on the existential type List[_] (might be wrong on how you say that, it's not the generic type that is existential, I think) and then cast. This is more or less exactly the problem you have, the type you're after has been erased, and there's no way to get it back (unless you can use the same trick with ClassManifest that can be used to get around type erasure in cases like the one above [but not actually the case above, because it's a bit sloppy]).

Related

Scala type inference and implicit conversions

The following code works:
scala> import scala.language.implicitConversions
import scala.language.implicitConversions
scala> implicit val longToInt = (l: Long) => l.toInt
longToInt: Long => Int = $$Lambda$1821/0x000000010086e840#52bd9a27
scala> def printInt(n: Int) = println(n)
printInt: (n: Int)Unit
scala> val opt: Option[Long] = None
opt: Option[Long] = None
scala> val n = opt.getOrElse(0L)
n: Long = 0
scala> printInt(n)
0
However, the compiler throws a type mismatch error if we nest the getOrElse expression inside of the function call:
scala> printInt(opt.getOrElse(0L))
<console>:16: error: type mismatch;
found : AnyVal
required: Int
printInt(opt.getOrElse(0L))
^
Why does opt.getOrElse(0L) have type AnyVal?
Scala 2.12.8
When you write
printInt(opt.getOrElse(0L))
opt.getOrElse(0L) is typed with expected type Int. Option#getOrElse's signature is
getOrElse[B >: A](default: ⇒ B): B
Because it's generic, the compiler tries to find B such that opt.getOrElse[B](0L) has type Int. So B has to satisfy constraints B >: Long (because A in the above signature is Long) and B <: Int (from the return type). Obviously there's no such B. Scala specification says this must be an error, but doesn't say which, and here the compiler happens to report it after guessing B = AnyVal.
Another way to fix it is to specify the expected type for opt.getOrElse(0L):
printInt(opt.getOrElse(0L): Long)
Or the type parameter:
printInt(opt.getOrElse[Long](0L))
The signature of getOrElse is:
def getOrElse[B1 >: B](key: A, default: ⇒ B1): B1
printInt(opt.getOrElse(0L)) tells Scala that B1 ought to be Long, but Long is not a super-type of Int. The common supertype instead is AnyVal. Therefore you cannot make that assignment.
Try casting the result to a Long instead:
printInt(opt.getOrElse(0L).toLong)

Convert Option to Either in Scala

Suppose I need to convert Option[Int] to Either[String, Int] in Scala. I'd like to do it like this:
def foo(ox: Option[Int]): Either[String, Int] =
ox.fold(Left("No number")) {x => Right(x)}
Unfortunately the code above doesn't compile and I need to add type Either[String, Int] explicitly:
ox.fold(Left("No number"): Either[String, Int]) { x => Right(x) }
Is it possible to convert Option to Either this way without adding the type ?
How would you suggest convert Option to Either ?
No, if you do it this way, you can't leave out the type.
The type of Left("No number") is inferred to be Either[String, Nothing]. From just Left("No number") the compiler can't know that you want the second type of the Either to be Int, and type inference doesn't go so far that the compiler will look at the whole method and decide it should be Either[String, Int].
You could do this in a number of different ways. For example with pattern matching:
def foo(ox: Option[Int]): Either[String, Int] = ox match {
case Some(x) => Right(x)
case None => Left("No number")
}
Or with an if expression:
def foo(ox: Option[Int]): Either[String, Int] =
if (ox.isDefined) Right(ox.get) else Left("No number")
Or with Either.cond:
def foo(ox: Option[Int]): Either[String, Int] =
Either.cond(ox.isDefined, ox.get, "No number")
I am not sure which version of Scala you were using at the time. Currently, with Scala 2.12.6 there's no compilation problems with your code like this:
def foo(ox: Option[Int]): Either[String, Int] =
ox.toRight("No number")
One other point I'd like to make is that folding (while it's my preferred method of collapsing just about anything that has a fold method on it) quite often requires help with type parameters. There's two ways the compiler can type check an expression, either it can infer the type parameters or it can simply find them explicitly defined.
In your example, if you're trying to fold an option like so:
def foo(ox: Option[Int]): Either[String, Int] =
ox.fold(Left("No number") : Either[String, Int])(x => Right(x))
You're explicitly providing type information about the first argument, which in turn can be then used to infer the type parameter of fold. You're aiding the type inference mechanism.
On the other hand, you could simply just explicitly provide the type parameter for fold like so:
def foo(ox: Option[Int]): Either[String, Int] =
ox.fold[Either[String, Int]](Left("No number"))(x => Right(x))
Now your actual (value-level) arguments are not littered with superfluous type information, and there's no type inference going on when the compiler looks at it, it can tell right away what fold's type parameter is, as it's been explicitly provided. Use the square brackets to specify the type parameter explicitly.
One more point, regarding x => Right(x) here you're practically creating a new function literal that does nothing other than pass x into the apply method of the Right case class's companion object. You already have a function of the appropriate shape available. It takes x and returns a Right(x). It is the apply method. You can refer to it (pass it) directly.
def foo(ox: Option[Int]): Either[String, Int] =
ox.fold[Either[String, Int]](Left("No number"))(Right.apply)
The reason why type annotation is necessary is because of the way type inference works in Scala 2 for multiple parameter lists where
parameter list are considered one at a time, and
constraints accumulated in first parameter lists are applied to the next parameter list.
Consider signature of Option#fold
def fold[B](ifEmpty: => B)(f: A => B): B
where we see type parameter B and two parameter lists. Now type of argument provided to the first parameter list is Left[String,Nothing] because
scala> Left("No number")
val res0: scala.util.Left[String,Nothing] = Left(No number)
which means type parameter B is inferred to be Left[String,Nothing], which in turn constrains the expected type of the argument provided to the second parameter list to be a function of Left return type
A => Left[String,Nothing]
however we are providing a function of Right return type, therefore it errors with type mismatch
Welcome to Scala 2.13.3 (OpenJDK 64-Bit Server VM, Java 1.8.0_252).
Type in expressions for evaluation. Or try :help.
scala> def foo(ox: Option[Int]): Either[String, Int] =
| ox.fold(Left("No number")) {x => Right(x)}
ox.fold(Left("No number")) {x => Right(x)}
^
On line 2: error: type mismatch;
found : scala.util.Right[Nothing,Int]
required: scala.util.Left[String,Nothing]
Note that Scala 3 (Dotty) brings improvements to type inference so your snippet would work out of the box without having to provide explicit type annotation
Starting dotty REPL...
scala> def foo(ox: Option[Int]): Either[String, Int] =
| ox.fold(Left("No number")) {x => Right(x)}
|
def foo(ox: Option[Int]): Either[String, Int]

Option getOrElse type mismatch error

Why does this code raise a type mismatch error in Scala 2.9.2? I expected that getOrElse returns type String but actually it returns java.io.Serializable:
scala> implicit def StringToOption(s:String) = Option(s)
StringToOption: (s: String)Option[String]
scala> "a".getOrElse("")
res0: String = a
scala> var opt:Option[String] = "a".getOrElse("")
<console>:8: error: type mismatch;
found : java.io.Serializable
required: Option[String]
var opt:Option[String] = "a".getOrElse("")
^
This is OK:
scala> implicit def StringToOption(s:String): Option[String] = Option(s)
StringToOption: (s: String)Option[String]
scala> var b:Option[String] = "a".getOrElse("") toString
b: Option[String] = Some(a)
It's an unwanted case of incomplete tree traversal. The signature of getOrElse allows type widening, so when it realizes that String is not Option[String] it first tries to fill in a different type ascription on getOrElse, i.e. Serializable. But now it has "a".getOrElse[Serializable]("") and it's stuck--it doesn't realize, I guess, that the problem was making the type too general before checking for implicits.
Once you realize the problem, there's a fix:
"a".getOrElse[String]("")
Now the typer doesn't wander down the let's-widen path, and finds the implicit.

Why does the explicit syntax for creating Tuples only allow AnyRefs as type annotations?

This code works:
scala> val x = ""
x: java.lang.String = ""
scala> Tuple2[x.type, x.type](x,x)
res5: (x.type, x.type) = ("","")
This one doesn't:
scala> val y = 0
y: Int = 0
scala> Tuple2[y.type, y.type](y,y)
<console>:9: error: type mismatch;
found : y.type (with underlying type Int)
required: AnyRef
Note: an implicit exists from scala.Int => java.lang.Integer, but
methods inherited from Object are rendered ambiguous. This is to avoid
a blanket implicit which would convert any scala.Int to any AnyRef.
You may wish to use a type ascription: `x: java.lang.Integer`.
Tuple2[y.type, y.type](y,y)
^
As well as this one:
scala> val z = ()
z: Unit = ()
scala> Tuple2[z.type, z.type](z,z)
<console>:9: error: type mismatch;
found : z.type (with underlying type Unit)
required: AnyRef
Note: Unit is not implicitly converted to AnyRef. You can safely
pattern match `x: AnyRef` or cast `x.asInstanceOf[AnyRef]` to do so.
Tuple2[z.type, z.type](z,z)
^
The language specification says
A singleton type is of the form p.type, where p is a path pointing to
a value expected to conform (§6.1) to scala.AnyRef.
What's the rationale behind that and would it make sense to lift that restriction like it recently happened with 0.getClass?
As you can see on Scala class hierarchy Int, Unit, Boolean (and others) are not subclasses of AnyRef, because they are translated into java int, void, boolean and so on, witch are not subclasses of Object.

Passing functions for all applicable types around

I followed the advice found here to define a function called square, and then tried to pass it to a function called twice. The functions are defined like this:
def square[T](n: T)(implicit numeric: Numeric[T]): T = numeric.times(n, n)
def twice[T](f: (T) => T, a: T): T = f(f(a))
When calling twice(square, 2), the REPL spits out an error message:
scala> twice(square, 2)
<console>:8: error: could not find implicit value for parameter numeric: Numeric[T]
twice(square, 2)
^
Anyone?
I disagree with everyone here except Andrew Phillips. Well, everyone so far. :-) The problem is here:
def twice[T](f: (T) => T, a: T): T = f(f(a))
You expect, like newcomers to Scala often do, for Scala's compiler to take into account both parameters to twice to infer the correct types. Scala doesn't do that, though -- it only uses information from one parameter list to the next, but not from one parameter to the next. That mean the parameters f and a are analyzed independently, without having the advantage of knowing what the other is.
That means, for instance, that this works:
twice(square[Int], 2)
Now, if you break it down into two parameter lists, then it also works:
def twice[T](a: T)(f: (T) => T): T = f(f(a))
twice(2)(square)
So, basically, everything you were trying to do was correct and should work, except for the part that you expected one parameter to help figuring out the type of the other parameter (as you wrote it).
Here's a session from the Scala REPL.
Welcome to Scala version 2.8.0.final (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_20).
Type in expressions to have them evaluated.
Type :help for more information.
scala> def square[T : Numeric](n: T) = implicitly[Numeric[T]].times(n, n)
square: [T](n: T)(implicit evidence$1: Numeric[T])T
scala> def twice2[T](f: T => T)(a: T) = f(f(a))
twice2: [T](f: (T) => T)(a: T)T
scala> twice2(square)(3)
<console>:8: error: could not find implicit value for evidence parameter of type
Numeric[T]
twice2(square)(3)
^
scala> def twice3[T](a: T, f: T => T) = f(f(a))
twice3: [T](a: T,f: (T) => T)T
scala> twice3(3, square)
<console>:8: error: could not find implicit value for evidence parameter of type
Numeric[T]
twice3(3, square)
scala> def twice[T](a: T)(f: T => T) = f(f(a))
twice: [T](a: T)(f: (T) => T)T
scala> twice(3)(square)
res0: Int = 81
So evidently the type of "twice(3)" needs to be known before the implicit can be resolved. I guess that makes sense, but I'd still be glad if a Scala guru could comment on this one...
Another solution is to lift square into partially applied function:
scala> twice(square(_:Int),2)
res1: Int = 16
This way the implicit is applied to square as in:
scala> twice(square(_:Int)(implicitly[Numeric[Int]]),2)
res3: Int = 16
There is even another approach:
def twice[T:Numeric](f: (T) => T, a: T): T = f(f(a))
scala> twice[Int](square,2)
res1: Int = 16
But again, the type parameter don't get inferred.
Your problem is that square isn't a function (ie. a scala.Function1[T, T] aka (T) => T). Instead it's a type parametrized method with multiple argument lists one of which is implicit ... there's no syntax in Scala to define an exactly equivalent function.
Interestingly, your use of the Numeric type class means that the usual encodings of higher-ranked functions in Scala don't directly apply here, but we can adapt them to this case and get something like this,
trait HigherRankedNumericFunction {
def apply[T : Numeric](t : T) : T
}
val square = new HigherRankedNumericFunction {
def apply[T : Numeric](t : T) : T = implicitly[Numeric[T]].times(t, t)
}
This gives us a higher-ranked "function" with its type parameter context-bounded to Numeric,
scala> square(2)
res0: Int = 4
scala> square(2.0)
res1: Double = 4.0
scala> square("foo")
<console>:8: error: could not find implicit value for evidence parameter of type Numeric[java.lang.String]
square("foo")
We can now define twice in terms of HigherRankedNumericFunctions,
def twice[T : Numeric](f : HigherRankedNumericFunction, a : T) : T = f(f(a))
scala> twice(square, 2)
res2: Int = 16
scala> twice(square, 2.0)
res3: Double = 16.0
The obvious downside of this approach is that you lose out on the conciseness of Scala's monomorphic function literals.