【问题标题】:enrich PartialFunction with unapply functionality用 unapply 功能丰富 PartialFunction
【发布时间】:2015-10-17 02:54:06
【问题描述】:

PartialFunction 是一个自然提取器,它的lift 方法提供了精确的提取器功能。所以使用部分函数作为提取器会非常方便。这将允许以比 PartialFunction 可用的普通 orElse 更复杂的方式组合模式匹配表达式

所以我尝试使用皮条客我的图书馆方法并失败了


这里更新:正如@Archeg 所示,还有另一种有效的转换方法。所以我将它包含在提供的代码中。

我也尝试了一些更复杂的解决方案,但都失败了


object Test {
  class UnapplyPartial[-R, +T](val fun : PartialFunction[R,T]) {
    def unapply(source : R) : Option[T] = fun.lift(source)
  }
  implicit def toUnapply[R,T](fun : PartialFunction[R,T]) : UnapplyPartial[R,T] = new UnapplyPartial(fun)

  class PartialFunOps[-R, +T](val fun : PartialFunction[R,T]) {
    def u : UnapplyPartial[R, T] = new UnapplyPartial(fun)
  }
  implicit def toPartFunOps[R,T](fun : PartialFunction[R,T]) : PartialFunOps[R,T] = new PartialFunOps(fun)


  val f : PartialFunction[String, Int] = {
    case "bingo" => 0
  }
  val u = toUnapply(f)

  def g(compare : String) : PartialFunction[String, Int] = {
    case `compare` => 0
  }

   // error while trying to use implicit conversion
  def testF(x : String) : Unit = x match {
    case f(i) => println(i)
    case _ => println("nothing")
  }

  // external explicit conversion is Ok
  def testU(x : String) : Unit = x match {
    case u(i) => println(i)
    case _ => println("nothing")
  }

 // embedded explicit conversion fails
  def testA(x : String) : Unit = x match {
    case toUnapply(f)(i) => println(i)
    case _ => println("nothing")
  }

  // implicit explicit conversion is Ok
  def testI(x : String) : Unit = x match {
    case f.u(i) => println(i)
    case _ => println("nothing")
  }

  // nested case sentences fails
  def testInplace(x : String) : Unit = x match {
    case { case "bingo" => 0 }.u(i) => println(i)
    case _ => println("nothing")
  }

  // build on the fly fails
  def testGen(x : String) : Unit = x match {
    case g("bingo").u(i) => println(i)
    case _ => println("nothing")
  }

  // implicit conversion without case is also Ok
  def testFA(x : String) : Option[Int] =
    f.unapply(x)
}

我收到以下错误消息:

UnapplyImplicitly.scala:16: 错误:值 f 不是案例类,也没有 unapply/unapplySeq 成员 案例 f(i) => println(i)

UnapplyImplicitly.scala:28: 错误:'=>' 预期但 '(' 找到。 case toUnapply(f)(i) => println(i)

使用TestI 所示的假定形式可以避免此错误。但我很好奇是否可以避免testInplace 错误:

UnapplyImplicitly.scala:46: 错误:简单模式的非法开始 案例 { 案例“宾果” => 0 }.u(i) => println(i) ^

UnapplyImplicitly.scala:47: 错误:'=>' 预期但 ';'成立。 case _ => println("nothing")

UnapplyImplicitly.scala:56: 错误:'=>' 预期但 '.'成立。 案例 g("bingo").u(i) => println(i) ^

【问题讨论】:

    标签: scala pattern-matching implicit-conversion


    【解决方案1】:

    我不确定您最终要达到什么目标,但据我了解,提取器应该始终是对象,您无法通过类获得它。它实际上在文档中称为Extractor Object。考虑一下:

    class Wrapper[R, T](fun: PartialFunction[R, T]) {
      object PartialExtractor {
        def unapply(p: R): Option[T] = fun.lift(p)
      }
    }
    
    implicit def toWrapper[R,T](fun : PartialFunction[R,T]) : Wrapper[R, T] = new Wrapper(fun)
    
    
    val f : PartialFunction[String, Int] = {
      case "bingo" => 0
    }
    
    def testFF(x : String) : Unit = x match {
      case f.PartialExtractor(i) => println(i)
      case _ => println("nothing")
    }
    

    更新

    我能想到的最好的:

    def testInplace(x : String) : Unit ={
      val ff = { case "bingo" => 0 } : PartialFunction[String, Int]
      x match {
       case ff.PartialExtractor(Test(i)) => println(i)
       case "sd" => println("nothing") }
    }
    

    【讨论】:

    • 真的很有效,谢谢。是否可以嵌套 case 表达式?
    • 当然。这就是为什么您想使用带有 unapply 的提取器,而不是使用原始 f.liftcase f.PartialExtractor(IntExtractor(i)) => ... 如果你有 object IntExtractor { def unapply(i: Int): Option[Int] = if (i == 0) Some(5) else None } 作品
    • 我很怀疑你可以在那里内联部分函数。 case 表达式是非常特殊的表达式,它不是 scala 表达式。例如,当所有大写的标识符都被视为类型/常量时,所有小写的标识符都被视为变量。 f.PartialExtractor 的情况很特殊,但它仍然是一个类型——它不是一个表达式,所以我认为你不能把表达式放在那里。我同意你不应该这样做 - 它看起来很丑而且很难阅读。您可以将一个函数放在方法的主体中,给它一个名称并使用它。查看更新
    • 我试过了,见更新。我将函数 g 定义为 String => PartialFunction[String, Int],它也被拒绝了
    • 正如我所说,case 表达式是一种非常特殊的表达式,你不能放任何东西。它由特殊规则解析。我相信你不能在那里调用任何方法,但如果你想了解更多关于它们是如何解析的,你可能应该查看 scala 编译器源代码。请注意,ff.PartialExtractor(..) 不是方法调用。如果您在正常的 scala 表达式中编写 ff.PartialExtractor(..),则会调用 .apply()。但万一表达式.unapply() 被调用。案例表达式与普通代码非常不同
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-19
    • 1970-01-01
    • 2014-01-21
    • 2010-09-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多