Type bounds on functions - scala

I am having trouble getting my code with parameterized types to pass the scala compiler. My goal is to be able to express (Predicate, Action) pairs as shown in the MyProg object.
trait ProgBase {
type Predicate[T] = T => Boolean
type Action[T] = T => Unit
private var prog = List[(Predicate[Any], Action[Any])]()
final def on[T <: Any](pred: Predicate[T])(action: Action[T]) = {
prog = (pred, action) :: prog // gives type mismatch
}
// remainder of trait elided
}
object MyProg extends ProgBase {
on[String](s => !s.isEmpty) { s =>
println(s + " is not empty")
}
on[Int](i => i.isValidByte) { i =>
println(i + " can fit in a byte")
}
}
By specifying that T has an upper bound of Any, I hoped this would appease the compiler, but clearly I am missing something:
[error] ......ProgBase.scala:8 type mismatch;
[error] found : (T => Boolean, T => Unit)
[error] required: (Any => Boolean, Any => Unit)
[error] prog = (pred, action) :: prog
[error] ^

First of all, answer to your question, if you write:
private var prog = List[(Predicate[_ <: Any], Action[_ <: Any])]()
It all compiles OK. We should use wildcards, 'cause the type of elements are unknown.
Second, maybe you mistyped, you can't use your on function as you used it, use it something like:
on[String](s => !s.isEmpty)(s => !s.isEmpty)
It caused by type mismatch: type Action[T] = T => Unit but println has type Unit,
so as a variant u can simply write: type Action = Unit. Obviously, u can avoid using this type alias at all.
Third, maybe you already know, and I shoudn't tell you, that in fact, you lose all information about predicate types - let's check it using Scala reflection:
import scala.reflect.runtime.{universe => ru}
def getTypeTag[T: ru.TypeTag](obj: T) = ru.typeTag[T]
val s: String = "123"
val i: Int = 123
on[String](s => !s.isEmpty)(s => !s.isEmpty)
on[Int](i => i.isValidByte)(i => i.isValidByte)
getTypeTag((MyProg.prog.head._1)).tpe =:= ru.typeOf[(String) => Boolean] //>false!
So you see the problem.
To deal with it you can use heterogeneous lists. Lists and other various powerful structures you can find in shapeless: https://github.com/milessabin/shapeless

Related

What is the difference between `Option.fold()()` and `Option.map().getOrElse()`?

The Option class has a method named fold(). The docs say:
sealed abstract class Option[+A]
fold[B](ifEmpty: ⇒ B)(f: (A) ⇒ B): B
Returns the result of applying f to this scala.Option's value if the scala.Option is nonempty. Otherwise, evaluates expression ifEmpty.
The docs continue:
This is equivalent to scala.Option map f getOrElse ifEmpty.
But is this really true? I've been told that under certain circumstances, with values of certain types, there are differences, but never with a decent explanation. What exactly are the situations where these two constructions will behave differently and why?
Option.fold is safer than .getOrElse. You can see the definition for .fold below, where both ifEmpty and f are of type B (introduced only after scala 2.10, probably):
#inline final def fold[B](ifEmpty: => B)(f: A => B): B =
if (isEmpty) ifEmpty else f(this.get)
which means you will probably not mess up the data types (exception below):
scala> val data = Option("massive data").fold(-1) { _ => 1 }
data: Int = 1
// but if I try to return different type in either of ifEmpty or f
// compiler will curse me right at my face
scala> val data = Option("massive data").fold(-1) { _ => "Let me get caught by compiler" }
<console>:17: error: type mismatch;
found : String("Let me get caught by compiler")
required: Int
val data = Option("massive data").fold(-1) { _ => "Let me get caught by compiler" }
^
While getOrElse is not as safe, unless you provide the type (supertype B in following definition) manually.
#inline final def getOrElse[B >: A](default: => B): B =
if (isEmpty) default else this.get
which means you can return a different type from getOrElse than what the original value wrapped in Option[A] was.
scala> val data = Option("massive data").map(_ => 1).getOrElse(List("I'm not integer"))
data: Any = 1
// you have to manually mention the type to getOrElse to restrict,
// which is not that smart in my opinion
scala> val data = Option("massive data").map(_ => 1).getOrElse[Int](List("I'm not integer"))
<console>:17: error: type mismatch;
found : List[String]
required: Int
val data = Option("massive data").map(_ => 1).getOrElse[Int](List("I'm not integer"))
^
The interesting thing is you can return unit from getOrElse or fold which can introduce bugs in an application unless you catch it in unit tests.
scala> val data = Option("massive data").fold() { _ => 1 }
data: Unit = ()
scala> val data = Option("massive data").map(_ => 1).getOrElse()
data: AnyVal = 1
As a counterpoint to #prayagupd's answer, fold often invites you to mess up types in a specific way.
The problem is that by Scala's rules, only ifEmpty is used to infer B and then f is checked to be suitable. Which means that using None or Nil as ifEmpty, which is quite common, will lead to their singleton types being used as B instead of Option/List[SomeType], no matter what f returns.
Of course, there are workarounds: specify B explicitly, use Option.empty[SomeType] or None: Option[SomeType] instead of None. Or just use pattern-matching.

Combine a PartialFunction with a regular function

So, suppose, I want to provide a "catch all" fall back for a PartialFunction:
val foo: PartialFunction[Int, String] = { case 1 => "foo" }
val withDefault = foo orElse { _.toString }
This does not compile: missing parameter type for expanded function ((x$1) => x$1.toString).
This:
val withDefault = foo orElse { case x: Int => x.toString }
Does not compile either (same error).
This:
val withDefault = foo orElse { (x: Int) => x.toString }
fails with type mismatch; found : Int => String; required: PartialFunction[?,?]
The only way I could find to make it work is to spell out the whole thing:
val withDefault = foo orElse PartialFunction[Int, String] { _.toString }
Is there any better syntax for this? I mean, one without having to tell it that I am passing a partial function from int to string to where it expects to receive a partial function from in to string. This is not ambiguous at all, why do I have to do this?
Maybe you need applyOrElse:
val withDefault = foo.applyOrElse(_: Int, (_: Int).toString)
Or maybe you would like something like this:
implicit class PartialFunToFun[A,B](val f: PartialFunction[A,B]) extends AnyVal {
def withDefault(bar: A => B) = f.applyOrElse[A,B](_: A, bar)
}
and use it: foo.withDefault(_.toString)(1)
Also if you want to get just another PartialFunction you can use the next syntax:
val withDefault = foo.orElse[Int, String]{case x => x.toString}
The errors you encountered for the first two are not specific to orElse. They also occur when you attempt to define the same functions separately.
scala> { _.toString }
<console>:12: error: missing parameter type for expanded function ((x$1: <error>) => x$1.toString)
{ _.toString }
scala> { case x: Int => x.toString }
<console>:12: error: missing parameter type for expanded function
The argument types of an anonymous function must be fully known. (SLS 8.5)
Expected type was: ?
{ case x: Int => x.toString }
^
For the last one, you are defining a function rather than a PartialFunction, thus leading to the "type mismatch" since orElse expects a PartialFunction to be passed.
scala> { (x: Int) => x.toString }
res3: Int => String = $$Lambda$1127/2044272973#3d5790ea
The final thing I'll add is that orElse is meant as a way to union two PartialFunctions. _.toString in itself is not a PartialFunction, though you could create a PartialFunction that uses it. To me it sounds like you want to have a "default" result for all the values that foo is not defined for, so I think you actually want applyOrElse instead since that is its use case. See the API to learn more.

Why doesn't the Scala compiler accept this lambda as a parameter?

Suppose I have an interface for a Thing:
abstract class Thing[A](a_thing: A) {
def thingA = a_thing
}
and I implement that Thing as follows:
class SpecificThing(a: String) extends Thing[String](a)
Furthermore, suppose I have a function that takes a Thing and a lambda that does something to that Thing as parameters:
def doSomething[A](fn: Thing[A] => A, t: Thing[A]) : A = fn(t)
Now, let's use this stuff:
val st = new SpecificThing("hi")
val fn1: (Thing[String]) => String = (t: Thing[String]) => { t.thingA }
println(doSomething(fn1, st))
This prints hi. So far, so good. But I'm lazy, and I don't like typing so much, so I change my program to the following:
type MyThing = Thing[String]
val st = new SpecificThing("hi")
val fn2: (MyThing) => String = (t: MyThing) => { t.thingA }
println(doSomething(fn2, st))
and this also prints hi. Fabulous! The compiler can tell that a SpecificThing is both a Thing[String] and a MyThing. But what about this case?
val st = new SpecificThing("hi")
val fn3: (SpecificThing) => String = (t: SpecificThing) => { t.thingA }
println(doSomething(fn3, st))
Now I get:
Error:(14, 23) type mismatch;
found : SpecificThing => String
required: Thing[?] => ?
println(doSomething(fn3, st))
^
What's going on? What's a Thing[?]?
f3 isn't a Thing[String] => String, it's a SpecificThing => String. For an example of why they couldn't be compatible:
class SpecificThing2 extends Thing[String] {
def thingB = 2.0
}
val f4: SpecificThing2 => String = {
st: SpecificThing2 => f"%f${st.thingB / 3.0}"
}
val t = new Thing[String]("haha"){}
f4(t) // would be an error when f4 tried to access t.thingB
More formally, Function1 is contravariant in its first type parameter, Function1[-T, +R].
A Thing[?] is what it looks like; it's a Thing[X] for some unknown type X. The compiler is gamely trying to infer what the type A should be, but it can't make it work: it needs a Thing[A] => A for some (unknown-to-it) type A, and you're passing it a SpecificThing => String; that's the error.

Match Value with Function based on Type

Suppose I have a list of functions as so:
val funcList = List(func1: A => T, func2: B => T, func2: C => T)
(where func1, et al. are defined elsewhere)
I want to write a method that will take a value and match it to the right function based on exact type (match a: A with func1: A => T) or throw an exception if there is no matching function.
Is there a simple way to do this?
This is similar to what a PartialFunction does, but I am not able to change the list of functions in funcList to PartialFunctions. I am thinking I have to do some kind of implicit conversion of the functions to a special class that knows the types it can handle and is able to pattern match against it (basically promoting those functions to a specialized PartialFunction). However, I can't figure out how to identify the "domain" of each function.
Thank you.
You cannot identify the domain of each function, because they are erased at runtime. Look up erasure if you want more information, but the short of it is that the information you want does not exist.
There are ways around type erasure, and you'll find plenty discussions on Stack Overflow itself. Some of them come down to storing the type information somewhere as a value, so that you can match on that.
Another possible solution is to simply forsake the use of parameterized types (generics in Java parlance) for your own customized types. That is, doing something like:
abstract class F1 extends (A => T)
object F1 {
def apply(f: A => T): F1 = new F1 {
def apply(n: A): T = f(n)
}
}
And so on. Since F1 doesn't have type parameters, you can match on it, and you can create functions of this type easily. Say both A and T are Int, then you could do this, for example:
F1(_ * 2)
The usual answer to work around type erasure is to use the help of manifests. In your case, you can do the following:
abstract class TypedFunc[-A:Manifest,+R:Manifest] extends (A => R) {
val retType: Manifest[_] = manifest[R]
val argType: Manifest[_] = manifest[A]
}
object TypedFunc {
implicit def apply[A:Manifest, R:Manifest]( f: A => R ): TypedFunc[A, R] = {
f match {
case tf: TypedFunc[A, R] => tf
case _ => new TypedFunc[A, R] { final def apply( arg: A ): R = f( arg ) }
}
}
}
def applyFunc[A, R, T >: A : Manifest]( funcs: Traversable[TypedFunc[A,R]] )( arg: T ): R = {
funcs.find{ f => f.argType <:< manifest[T] } match {
case Some( f ) => f( arg.asInstanceOf[A] )
case _ => sys.error("Could not find function with argument matching type " + manifest[T])
}
}
val func1 = { s: String => s.length }
val func2 = { l: Long => l.toInt }
val func3 = { s: Symbol => s.name.length }
val funcList = List(func1: TypedFunc[String,Int], func2: TypedFunc[Long, Int], func3: TypedFunc[Symbol, Int])
Testing in the REPL:
scala> applyFunc( funcList )( 'hello )
res22: Int = 5
scala> applyFunc( funcList )( "azerty" )
res23: Int = 6
scala> applyFunc( funcList )( 123L )
res24: Int = 123
scala> applyFunc( funcList )( 123 )
java.lang.RuntimeException: Could not find function with argument matching type Int
at scala.sys.package$.error(package.scala:27)
at .applyFunc(<console>:27)
at .<init>(<console>:14)
...
I think you're misunderstanding how a List is typed. List takes a single type parameter, which is the type of all the elements of the list. When you write
val funcList = List(func1: A => T, func2: B => T, func2: C => T)
the compiler will infer a type like funcList : List[A with B with C => T].
This means that each function in funcList takes a parameter that is a member of all of A, B, and C.
Apart from this, you can't (directly) match on function types due to type erasure.
What you could instead do is match on a itself, and call the appropriate function for the type:
a match {
case x : A => func1(x)
case x : B => func2(x)
case x : C => func3(x)
case _ => throw new Exception
}
(Of course, A, B, and C must remain distinct after type-erasure.)
If you need it to be dynamic, you're basically using reflection. Unfortunately Scala's reflection facilities are in flux, with version 2.10 released a few weeks ago, so there's less documentation for the current way of doing it; see How do the new Scala TypeTags improve the (deprecated) Manifests?.

What's the difference of the two method definition?

What's the difference of the following definition?
1.def debug(msg: => AnyRef) = { println(String.valueOf(msg)) }
2.def debug(msg: () => AnyRef) = { println(String.valueOf(msg)) }
The first definition can accept any thing, string, or function etc. but the second one can only accept function. I'd like to know reazon.
scala> def debug(msg: => AnyRef) = { println(String.valueOf(msg)) }
debug: (msg: => AnyRef)Unit
scala> debug("hi")
hi
scala> debug(() => "xx")
<function0>
scala> def debug(msg: () => AnyRef) = { println(String.valueOf(msg)) }
debug: (msg: () => AnyRef)Unit
scala> debug("hi")
<console>:9: error: type mismatch;
found : java.lang.String("hi")
required: () => AnyRef
debug("hi")
^
The first is a call-by-name parameter, i.e. it evaluates the the argument each time it is used in the method, and only if it is used. As you have discovered, this can be anthing that evaluates to the required type.
The second takes specifically a Function0[AnyRef] object. You can think of the () as an empty parameter list (not to be confused with the Unit value, which is written the same).