Scala Multiple Inheritance: Differentiate between Iterable and PartialFunction in method arguments - scala

I want to be able to define a method with the same name that has a different implementation if the argument is an Iterable[T1] vs a function: T1 => T2
However, many classes that implement Iterable also implement PartialFunction
For example:
object FunList {
def foo(itr: Iterable[Int]) = println("hello")
def foo(f: (Int => Int)) = println("Goodbye")
}
scala> FunList.foo(List(1))
<console>:9: error: ambiguous reference to overloaded definition,
both method foo in object FunList of type (f: Int => Int)Unit
and method foo in object FunList of type (itr: Iterable[Int])Unit
match argument types (List[Int])
FunList.foo(List(1))
currently my solution looks like this, but it does not match subclasses of Iterable which are not also subclasses of PartialFunction
case class SeqOrFun[T1, T2](f: (T1 => T2))
implicit def seqOrFun[T1, T2](f: (T1 => T2)) = SeqOrFun(f)
def unfurl[T1: Numeric, T2: Numeric](x: SeqOrFun[T1, T2], y: SeqOrFun[T1, T2]) = {
(x.f, y.f) match {
case (xs: Iterable[T1], ys: Iterable[T2]) => (xs, ys)
case (xf: (T2 => T1), ys: Iterable[T2]) => (ys.map(xf), ys)
case (xs: Iterable[T1], yf: (T1 => T2)) => (xs, xs.map(yf))
}
}

Since List is both Iterable[Int] and Int => Int, as you've said, what you're writing is inherently abmiguous. Perhaps I've misread, but I don't see any place at all where you've specified whether you want FunList.foo(List(1)) to print "hello" or "Goodbye".
First, you can use a cast at the call site. I assume you already know this, but just to be explicit for the sake of discussion:
FunList.foo(List(1): Int => Int) // "hello"
FunList.foo(List(1): Iterable[Int]) // "Goodbye"
If our objective here is to allow the caller to simply write FunList.foo(List(1)), you could use the magnet pattern. This means you don't use method overloading at all; instead you write a single method, and the dispatch is done with implicit conversions.
sealed trait FooMagnet
case class HelloMagnet(itr: Iterable[Int]) extends FooMagnet
case class GoodbyeMagnet(f: Int => Int) extends FooMagnet
def foo(x: FooMagnet): Unit = x match {
case HelloMagnet(itr) => println("hello")
case GoodbyeMagnet(f) => println("Goodbye")
}
def a(): Unit = {
implicit def listIsHelloMagnet(x: List[Int]): FooMagnet = HelloMagnet(x)
FunList.foo(List(1)) // "hello"
}
def b(): Unit = {
implicit def listIsGoodbyeMagnet(x: List[Int]): FooMagnet = GoodbyeMagnet(x)
FunList.foo(List(1)) // "Goodbye"
}
The fun advantage you get here is that the dispatch decision is decoupled from the foo implementation, since it's determined by those implicits which you can define wherever you like.
You can also use this to resolve the ambiguity problem! Start with the two implicits from earlier:
implicit def iterableIsHelloMagnet(x: Iterable[Int]): FooMagnet = HelloMagnet(x)
implicit def functionIsGoodbyeMagnet(x: Int => Int): FooMagnet = GoodbyeMagnet(x)
And then add another implicit specifically for List[Int].
implicit def listIsHelloMagnet(x: List[Int]): FooMagnet = HelloMagnet(x)
Scala is clever enough to see that this third conversion is more specific than the first two, so it will use that one for List[Int] even though they all apply. Thus we can now write:
FunList.foo(Set(1)) // "hello"
FunList.foo((_: Int) + 1) // "Goodbye"
FunList.foo(List(1)) // "hello"
And you can move the definitions of those implicits into the called library, so all the caller has to do is import them.

Related

Anonymous PartialFunction syntax

I asked this question earlier: Combine a PartialFunction with a regular function
and then realized, that I haven't actually asked it right.
So, here goes another attempt.
If I do this:
val foo = PartialFunction[Int, String] { case 1 => "foo" }
val bar = foo orElse { case x => x.toString }
it does not compile: error: missing parameter type for expanded function
The argument types of an anonymous function must be fully known. (SLS 8.5)
Expected type was: PartialFunction[?,?]
But this works fine:
val x: Seq[String] = List(1,2,3).collect { case x => x.toString }
The question is what is the difference? The type of the argument is the same in both cases: PartialFunction[Int, String]. The value passed in is literally identical. Why one does one case work, but not the other?
You need to specify the type for bar because the compiler is unable to infer it. This compiles:
val foo = PartialFunction[Int, String] { case 1 => "foo" }
val bar : (Int => String) = foo orElse { case x => x.toString }
In the case of List(1,2,3).collect{case x => x.toString} the compiler is able to infer the input type of the partial function based off of how theList was typed.
final override def collect[B, That](pf: PartialFunction[A, B])(implicit bf: CanBuildFrom[List[A], B, That])
Based on the type parameters the compiler can infer that you are passing a correctly typed partial function. That's why List(1,2,3).collect{case x:String => x.toString} does not compile nor does List(1,2,3).collect{case x:Int => x.toString; case x: String => x.toString}.
Since List is covariant the compiler is able to infer that the partial function {case x => x.toString} is a partial function on Int. You'll notice that List(1,2,3).collect{case x => x.length} does not compile because the compiler is inferring that you're operating on either an Int or a subclass of Int.
Also keep in mind that the {case x => x.toString} is just syntactic sugar. If we do something like the below then your example works as expected
val f = new PartialFunction[Int, String](){
override def isDefinedAt(x: Int): Boolean = true
override def apply(v1: Int): String = v1.toString
}
val foo = PartialFunction[Int, String] { case 1 => "foo" }
val bar = foo orElse f //This compiles fine.
List(1,2,3).collect{f} // This works as well.
So the only logical answer from my perspective is that the syntactic sugar that is able to generate a PartialFunction instance for {case x => x.toString} does not have enough information at compile time to be able to adequately type it as a PartialFunction[Int, String] in your orElse case.
You can use the library Extractor.scala.
import com.thoughtworks.Extractor._
// Define a PartialFunction
val pf: PartialFunction[Int, String] = {
case 1 => "matched by PartialFunction"
}
// Define an optional function
val f: Int => Option[String] = { i =>
if (i == 2) {
Some("matched by optional function")
} else {
None
}
}
// Convert an optional function to a PartialFunction
val pf2: PartialFunction[Int, String] = f.unlift
util.Random.nextInt(4) match {
case pf.extract(m) => // Convert a PartialFunction to a pattern
println(m)
case f.extract(m) => // Convert an optional function to a pattern
println(m)
case pf2.extract(m) => // Convert a PartialFunction to a pattern
throw new AssertionError("This case should never occur because it has the same condition as `f.extract`.")
case _ =>
println("Not matched")
}

Converting a List to a Case Class

As an exercise, I am trying to see if I can take a List[Any] and "cast" it into a case class using shapeless.
A very basic example of what I am trying to achieve:
case class Foo(i: Int, j: String)
val foo: Option[Foo] = fromListToCaseClass[Foo]( List(1:Any, "hi":Any) )
Here is how I am shaping my solution (this can be quite off):
def fromListToCaseClass[CC <: Product](a: List[Any]): Option[CC] = a.toHList[???].map( x => Generic[CC].from(x) )
Here is my reasoning:
I know that you can go from a case class to an HList[T] (CC -> HList[T]); where T is the type of the HList. I also know that you can create an HList from a list (list -> Option[HList]) as long as you know the type of the HList. Finally I know that you can go from an HList to a case class (HList -> CC).
CC -> HList[T]
list -> Option[HList[T]] -> Option[CC]
I am wondering if this makes sense or if I am way off here. Can we make this work? Any other suggestions? Thanks!
This can be done very straightforwardly using shapeless's Generic and FromTraversable type classes,
import scala.collection.GenTraversable
import shapeless._, ops.traversable.FromTraversable
class FromListToCaseClass[T] {
def apply[R <: HList](l: GenTraversable[_])
(implicit gen: Generic.Aux[T, R], tl: FromTraversable[R]): Option[T] =
tl(l).map(gen.from)
}
def fromListToCaseClass[T] = new FromListToCaseClass[T]
(There's some accidental complexity here due to Scala's awkwardness when it comes to mixing explicit and inferred type parameters: we want to specify T explicitly, but have R inferred for us).
Sample REPL session ...
scala> case class Foo(i: Int, j: String)
defined class Foo
scala> fromListToCaseClass[Foo](List(23, "foo"))
res0: Option[Foo] = Some(Foo(23,foo))
scala> fromListToCaseClass[Foo](List(23, false))
res1: Option[Foo] = None
You can do it with shapeless the following way:
import shapeless._
trait Creator[A] { def apply(list:List[Any]): Option[A] }
object Creator {
def as[A](list: List[Any])(implicit c: Creator[A]): Option[A] = c(list)
def instance[A](parse: List[Any] => Option[A]): Creator[A] = new Creator[A] {
def apply(list:List[Any]): Option[A] = parse(list)
}
def arbitraryCreate[A] = instance(list => list.headOption.map(_.asInstanceOf[A]))
implicit val stringCreate = arbitraryCreate[String]
implicit val intCreate = arbitraryCreate[Int]
implicit val hnilCreate = instance(s => if (s.isEmpty) Some(HNil) else None)
implicit def hconsCreate[H: Creator, T <: HList: Creator]: Creator[H :: T] =
instance {
case Nil => None
case list => for {
h <- as[H](list)
t <- as[T](list.tail)
} yield h :: t
}
implicit def caseClassCreate[C, R <: HList](
implicit gen: Generic.Aux[C, R],
rc: Creator[R]): Creator[C] =
instance(s => rc(s).map(gen.from))
}
And
val foo:Option[Foo] = Creator.as[Foo](List(1, "hi"))

Overcoming Scala Type Erasure For Function Argument of Higher-Order Function

Essentially, what I would like to do is write overloaded versions of "map" for a custom class such that each version of map differs only by the type of function passed to it.
This is what I would like to do:
object Test {
case class Foo(name: String, value: Int)
implicit class FooUtils(f: Foo) {
def string() = s"${f.name}: ${f.value}"
def map(func: Int => Int) = Foo(f.name, func(f.value))
def map(func: String => String) = Foo(func(f.name), f.value)
}
def main(args: Array[String])
{
def square(n: Int): Int = n * n
def rev(s: String): String = s.reverse
val f = Foo("Test", 3)
println(f.string)
val g = f.map(rev)
val h = g.map(square)
println(h.string)
}
}
Of course, because of type erasure, this won't work. Either version of map will work alone, and they can be named differently and everything works fine. However, it is very important that a user can call the correct map function simply based on the type of the function passed to it.
In my search for how to solve this problem, I cam across TypeTags. Here is the code I came up with that I believe is close to correct, but of course doesn't quite work:
import scala.reflect.runtime.universe._
object Test {
case class Foo(name: String, value: Int)
implicit class FooUtils(f: Foo) {
def string() = s"${f.name}: ${f.value}"
def map[A: TypeTag](func: A => A) =
typeOf[A] match {
case i if i =:= typeOf[Int => Int] => f.mapI(func)
case s if s =:= typeOf[String => String] => f.mapS(func)
}
def mapI(func: Int => Int) = Foo(f.name, func(f.value))
def mapS(func: String => String) = Foo(func(f.name), f.value)
}
def main(args: Array[String])
{
def square(n: Int): Int = n * n
def rev(s: String): String = s.reverse
val f = Foo("Test", 3)
println(f.string)
val g = f.map(rev)
val h = g.map(square)
println(h.string)
}
}
When I attempt to run this code I get the following errors:
[error] /src/main/scala/Test.scala:10: type mismatch;
[error] found : A => A
[error] required: Int => Int
[error] case i if i =:= typeOf[Int => Int] => f.mapI(func)
[error] ^
[error] /src/main/scala/Test.scala:11: type mismatch;
[error] found : A => A
[error] required: String => String
[error] case s if s =:= typeOf[String => String] => f.mapS(func)
It is true that func is of type A => A, so how can I tell the compiler that I'm matching on the correct type at runtime?
Thank you very much.
In your definition of map, type A means the argument and result of the function. The type of func is then A => A. Then you basically check that, for example typeOf[A] =:= typeOf[Int => Int]. That means func would be (Int => Int) => (Int => Int), which is wrong.
One of ways of fixing this using TypeTags looks like this:
def map[T, F : TypeTag](func: F)(implicit ev: F <:< (T => T)) = {
func match {
case func0: (Int => Int) #unchecked if typeOf[F] <:< typeOf[Int => Int] => f.mapI(func0)
case func0: (String => String) #unchecked if typeOf[F] <:< typeOf[String => String] => f.mapS(func0)
}
}
You'd have to call it with an underscore though: f.map(rev _). And it may throw match errors.
It may be possible to improve this code, but I'd advise to do something better. The simplest way to overcome type erasure on overloaded method arguments is to use DummyImplicit. Just add one or several implicit DummyImplicit arguments to some of the methods:
implicit class FooUtils(f: Foo) {
def string() = s"${f.name}: ${f.value}"
def map(func: Int => Int)(implicit dummy: DummyImplicit) = Foo(f.name, func(f.value))
def map(func: String => String) = Foo(func(f.name), f.value)
}
A more general way to overcome type erasure on method arguments is to use the magnet pattern. Here is a working example of it:
sealed trait MapperMagnet {
def map(foo: Foo): Foo
}
object MapperMagnet {
implicit def forValue(func: Int => Int): MapperMagnet = new MapperMagnet {
override def map(foo: Foo): Foo = Foo(foo.name, func(foo.value))
}
implicit def forName(func: String => String): MapperMagnet = new MapperMagnet {
override def map(foo: Foo): Foo = Foo(func(foo.name), foo.value)
}
}
implicit class FooUtils(f: Foo) {
def string = s"${f.name}: ${f.value}"
// Might be simply `def map(func: MapperMagnet) = func.map(f)`
// but then it would require those pesky underscores `f.map(rev _)`
def map[T](func: T => T)(implicit magnet: (T => T) => MapperMagnet): Foo =
magnet(func).map(f)
}
This works because when you call map, the implicit magnet is resolved at compile time using full type information, so no erasure happens and no runtime type checks are needed.
I think the magnet version is cleaner, and as a bonus it doesn't use any runtime reflective calls, you can call map without underscore in the argument: f.map(rev), and also it can't throw runtime match errors.
Update:
Now that I think of it, here magnet isn't really simpler than a full typeclass, but it may show the intention a bit better. It's a less known pattern than typeclass though. Anyway, here is the same example using the typeclass pattern for completeness:
sealed trait FooMapper[F] {
def map(foo: Foo, func: F): Foo
}
object FooMapper {
implicit object ValueMapper extends FooMapper[Int => Int] {
def map(foo: Foo, func: Int => Int) = Foo(foo.name, func(foo.value))
}
implicit object NameMapper extends FooMapper[String => String] {
def map(foo: Foo, func: String => String) = Foo(func(foo.name), foo.value)
}
}
implicit class FooUtils(f: Foo) {
def string = s"${f.name}: ${f.value}"
def map[T](func: T => T)(implicit mapper: FooMapper[T => T]): Foo =
mapper.map(f, func)
}

Implicit conversion with generic implicit parameter

I seems that combining implicit conversions with generic implicit parameters does not work, as in example 2b below:
object Test {
case class Foo(i: Int)
case class Bar(i: Int)
case class Zip(i: Int)
object Foo {
// 1)
implicit def toBar(foo: Foo)(implicit g: Int => Bar): Bar = g(foo.i)
// 2)
implicit def toT[T](foo: Foo)(implicit g: Int => T): T = g(foo.i)
}
// 1)
implicit val b = (i: Int) => Bar(i)
val bar: Bar = Foo(3)
// 2a)
implicit val z = (i: Int) => Zip(i)
val zip: Zip = Foo.toT(Foo(3))
// 2b)
val zip2: Zip = Foo(3) // <- compiler error, implicit conversion not applied
}
Is there any theoretical reason why this doesn't work, or is it a limitation of the implementation?
For what it's worth, if you run the following reduced version of your code
case class Foo(i: Int)
case class Zip(i: Int)
implicit def toT[T](foo: Foo)(implicit g: Int => T): T = g(foo.i)
implicit val z = (i: Int) => Zip(i)
val zip2: Zip = Foo(3) // <- compiler error, implicit conversion not applied
with -Yinfer-debug, you'll get lots of debug information (Scala 2.9.2) about what is going on behind the scenes. I am not familiar with Scala compiler internals, but the following two output snippets might hint at the problem. The first one is (line 51ff of the gist)
[inferImplicit view] pt = this.Foo => this.Zip
Implicit search in Context(Main.$anon.zip2#ValDef scope=1100551785) {
search this.Foo => this.Zip
target $anon.this.Foo.apply(3)
isView true
eligible toT: [T](foo: this.Foo)(implicit g: Int => T)T
}
and I interpret it as "we are looking for an implicit this.Foo => this.Zip and a candidate worth looking at is toT: [T](foo: this.Foo)(implicit g: Int => T)T.
This snippet is followed by output that suggests that Scala then tries to instantiate T, but line 81 finally says
inferMethodInstance, still undetermined: List(type T)
My interpretation is, that Scala somehow fails to instantiate T with Zip, which is why the candidate is finally discarded.
That said, I don't see a theoretical problem with your code, and I assume that it is only a shortcoming of the compiler.

Why is PartialFunction <: Function in Scala?

In Scala, the PartialFunction[A, B] class is derived from type Function[A, B] (see Scala Reference, 12.3.3). However, this seems counterintuitive to me, since a Function (which needs to be defined for all A) has more stringent requirements than a PartialFunction, which can be undefined at some places.
The problem I've come across is that when I have a partial function, I cannot use a Function to extend the partial function. Eg. I cannot do:
(pf orElse (_)=>"default")(x)
(Hope the syntax is at least remotely right)
Why is this subtyping done reversely? Are there any reasons that I've overlooked, like the fact that the Function types are built-in?
BTW, it would be also nice if Function1 :> Function0 so I needn't have the dummy argument in the example above :-)
Edit to clarify the subtyping problem
The difference between the two approaches can be emphasized by looking at two examples. Which of them is right?
One:
val zeroOne : PartialFunction[Float, Float] = { case 0 => 1 }
val sinc = zeroOne orElse ((x) => sin(x)/x) // should this be a breach of promise?
Two:
def foo(f : (Int)=>Int) {
print(f(1))
}
val bar = new PartialFunction[Int, Int] {
def apply(x : Int) = x/2
def isDefinedAt(x : Int) = x%2 == 0
}
foo(bar) // should this be a breach of promise?
Because in Scala (as in any Turing complete language) there is no guarantee that a Function is total.
val f = {x : Int => 1 / x}
That function is not defined at 0. A PartialFunction is just a Function that promises to tell you where it's not defined. Still, Scala makes it easy enough to do what you want
def func2Partial[A,R](f : A => R) : PartialFunction[A,R] = {case x => f(x)}
val pf : PartialFunction[Int, String] = {case 1 => "one"}
val g = pf orElse func2Partial{_ : Int => "default"}
scala> g(1)
res0: String = one
scala> g(2)
res1: String = default
If you prefer, you can make func2Partial implicit.
PartialFunction has methods which Function1 does not, therefore it is the subtype. Those methods are isDefinedAt and orElse.
Your real problem is that PartialFunctions are not inferred sometimes when you'd really like them to be. I'm hopeful that will be addressed at some future date. For instance this doesn't work:
scala> val pf: PartialFunction[String, String] = { case "a" => "foo" }
pf: PartialFunction[String,String] = <function>
scala> pf orElse { case x => "default" }
<console>:6: error: missing parameter type for expanded function
((x0$1) => x0$1 match { case (x # _) => "default" })
But this does:
scala> pf orElse ({ case x => "default" } : PartialFunction[String,String])
res5: PartialFunction[String,String] = <function>
Of course you could always do this:
scala> implicit def f2pf[T,R](f: Function1[T,R]): PartialFunction[T,R] =
new PartialFunction[T,R] {
def apply(x: T) = f(x)
def isDefinedAt(x: T) = true
}
f2pf: [T,R](f: (T) => R)PartialFunction[T,R]
And now it's more like you want:
scala> pf orElse ((x: String) => "default")
res7: PartialFunction[String,String] = <function>
scala> println(res7("a") + " " + res7("quux"))
foo default