如何在Function1或PartialFunction上实现扩展功能

时间:2013-11-07 04:07:31

标签: scala higher-order-functions erasure

我想在Function1或PartialFunction上定义一个扩展函数。

我想这样做,因为我有一个类似于以下的用例:

class A
class B extends A

def foo(fun: Function[B, A]) = {
    bar(fun.widen[A])
}

def bar(pf: PartialFunction[A, A]) = ???

从上面可以看出,为了实现这一点,我想到了定义这样一个扩展函数:

implicit class AugmentedFunction[T, U](fun: T => U) {
    def widen[T1 >: T]: PartialFunction[T1, U] = { case t: T => fun(t) }
}

但不幸的是,由于擦除,这不起作用。我试着使用TypeTags,但我似乎无法以满足编译器的方式表达这一点。

澄清: 当我说它不起作用时,我的意思是它在使用时会引发异常(请参阅ScalaKata代码片段),它实际上不应该抛出异常并在ScalaKata上的代码片段的特定情况下打印“未定义”。

我的问题

我怎样才能正确解决这个问题? Scalaz或Shapeless中是否已存在我不知道的功能?首先要做到这一点是否有意义?

以下是包含所有代码的代码段:http://www.scalakata.com/527bb729e4b0b1a1c4db1a73

3 个答案:

答案 0 :(得分:3)

我认为你可以用课堂清单来做到这一点:

implicit class AugmentedFunction[T, U](fun: T => U)(implicit m: Manifest[T]) {
  def widen[T1](implicit m1: Manifest[T1]): PartialFunction[T1, U] = {
    case a if(m <:< m1) => fun(a.asInstanceOf[T]) 
  }
}

class A
class B extends A
class C

val theFun: B => A = (b: B) => b

theFun.widen[A].isDefinedAt(new B) // true
theFun.widen[C].isDefinedAt(new C) // false

答案 1 :(得分:0)

错误说明了一切:java.lang.ClassCastException: ScalaKata$A$1 cannot be cast to ScalaKata$B$1。基本上,当您调用foo( (a: B) => new A, new A)时,A值将传递给lambda,该lambda实际上接受类型B作为param,因此从A转换为B时会出现异常因为不可能从泛型转换为特定的。

你必须使用类似的东西:

foo( (a: Ai) => new Ai, new Ai)
foo( (a: Ci) => new Ai, new Ci)
foo( (a: Ai) => new Ai, new Bi)

基本上,第二个参数应该是lambda参数类型的子类型。

答案 2 :(得分:0)

使用TypeTag实施(因为Manifest已被弃用)

import scala.reflect.runtime.universe._

implicit class AugmentedFunction[T : TypeTag, U](fun: T => U) {
  def widen[T1 : TypeTag]: PartialFunction[T1, U] = {
    case a if typeOf[T] <:< typeOf[T1] => fun(a.asInstanceOf[T])
  }
}