2

假设我有部分功能parf

val parf: PartialFunction[Int, String] = { case 0 => "!!!" }

现在我也有了case class A(x: Int),我需要一个函数来转换PartialFunction[Int, String]PartialFunction[A, String]

def foo(pf: PartialFunction[Int, String]): PartialFunction[A, String] = ???

例如,foo(parf)应该返回{case A(0) => "!!!" }. 你会怎么写函数foo

4

3 回答 3

4

为了保持正确的功能,您需要检查内部偏函数是否定义在您要传递的参数上:

val parf: PartialFunction[Int, String] = { case 0 => "!!!" }

case class A(x: Int)

def foo(pf: PartialFunction[Int, String]): PartialFunction[A, String] = {
  case A(i) if pf.isDefinedAt(i) => pf(i)
}

如果您打算在更大范围内执行此操作,您可能希望将部分函数转换为提取器对象,以便可以使用更好的语法直接在模式匹配中使用它:

trait Extractor[A, B] {
  def unapply(a: A): Option[B]
}

object Extractor {
  implicit def partialFunctionAsExtractor[A, B](pf: PartialFunction[A, B]): Extractor[A, B] =
    new Extractor[A, B] {
      def unapply(a: A) = if (pf.isDefinedAt(a)) Some(pf(a)) else None
    }
}

def foo2(pf: Extractor[Int, String]): PartialFunction[A, String] = {
    case A(pf(str)) => str
}

foo2(parf) // implicit conversion magic
于 2018-02-05T08:19:53.297 回答
3

我不明白是什么让你对此感到困惑?你只需要匹配提取Int出来,A然后让 PF 按照它想要的方式运行。

scala> case class A(x: Int)
// defined class A

scala> val parf: PartialFunction[Int, String] = { case 0 => "!!!" }
// parf: PartialFunction[Int,String] = <function1>

scala> def foo(pf: PartialFunction[Int, String]): PartialFunction[A, String] = { 
     |   case A(x) if pf.isDefinedAt(x) => pf(x)
     | }   
// foo: (pf: PartialFunction[Int,String])PartialFunction[A,String]

scala> val parfA = foo(parf)
// parfA: PartialFunction[A,String] = <function1>

scala> parfA(A(0))
//res0: String = !!!

scala> parfA(A(1))
// scala.MatchError: A(1) (of class A)
//   at scala.PartialFunction$$anon$1.apply(PartialFunction.scala:254)
//   at scala.PartialFunction$$anon$1.apply(PartialFunction.scala:252)
//   at $anonfun$1.applyOrElse(<console>:11)
//   at $anonfun$1.applyOrElse(<console>:11)
//   at scala.runtime.AbstractPartialFunction.apply(AbstractPartialFunction.scala:34)
//   at $anonfun$foo$1.applyOrElse(<console>:13)
//   at $anonfun$foo$1.applyOrElse(<console>:13)
//   at scala.runtime.AbstractPartialFunction.apply(AbstractPartialFunction.scala:34)
//   ... 28 elided
于 2018-02-05T08:11:29.653 回答
1

@Oleg Pyzhcov 已经提供了一个很好的解决方案。另一种方法是创建一个在 A(0) 处定义的 PartialFunction[A, Int],并将andThen其与 链接parf

val parf: PartialFunction[Int, String] = { case 0 => "!!!" }

case class A(n: Int)

val bar: PartialFunction[A, Int] = { case a: A if a.n == 0 => a.n }

def foo(pf: PartialFunction[Int, String]): PartialFunction[A, String] =
  bar andThen pf
// foo: (pf: PartialFunction[Int,String])PartialFunction[A,String]

foo(parf)
// res1: PartialFunction[A,String] = <function1>
于 2018-02-06T01:39:29.923 回答