2

我想在 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

4

3 回答 3

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
于 2013-11-07T15:41:34.370 回答
0

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

你必须使用类似的东西:

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

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

于 2013-11-07T05:45:59.177 回答
0

通过 using 实现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])
  }
} 
于 2013-11-13T09:01:52.900 回答