如何将一个偏函数转换为另一个偏函数?
How to convert one partial function to another?
假设我有部分功能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)
应该return{case A(0) => "!!!" }
。你会怎么写 function foo
?
我不明白是什么让你感到困惑?您只需要从 A
中匹配提取 Int
,然后让 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.apply(PartialFunction.scala:254)
// at scala.PartialFunction$$anon.apply(PartialFunction.scala:252)
// at $anonfun.applyOrElse(<console>:11)
// at $anonfun.applyOrElse(<console>:11)
// at scala.runtime.AbstractPartialFunction.apply(AbstractPartialFunction.scala:34)
// at $anonfun$foo.applyOrElse(<console>:13)
// at $anonfun$foo.applyOrElse(<console>:13)
// at scala.runtime.AbstractPartialFunction.apply(AbstractPartialFunction.scala:34)
// ... 28 elided
为了保持正确的功能,您需要检查内部部分函数是否定义在您要传递的参数上:
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
@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>
假设我有部分功能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)
应该return{case A(0) => "!!!" }
。你会怎么写 function foo
?
我不明白是什么让你感到困惑?您只需要从 A
中匹配提取 Int
,然后让 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.apply(PartialFunction.scala:254)
// at scala.PartialFunction$$anon.apply(PartialFunction.scala:252)
// at $anonfun.applyOrElse(<console>:11)
// at $anonfun.applyOrElse(<console>:11)
// at scala.runtime.AbstractPartialFunction.apply(AbstractPartialFunction.scala:34)
// at $anonfun$foo.applyOrElse(<console>:13)
// at $anonfun$foo.applyOrElse(<console>:13)
// at scala.runtime.AbstractPartialFunction.apply(AbstractPartialFunction.scala:34)
// ... 28 elided
为了保持正确的功能,您需要检查内部部分函数是否定义在您要传递的参数上:
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
@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>