优雅的方式链接Scala部分功能

时间:2016-12-07 10:27:13

标签: scala

我正在寻找一种优雅的方法来链接从公共基类型派生的部分函数。我们的想法是每个部分函数处理一个类型,因此如果链接的部分函数未定义,它们就很容易为不同的类型组合并具有共同的特征:

trait Message
trait SysMessage extends Message
trait UserMessage extends Message

case class TextSysMessage(m: String) extends SysMessage
case class TextUserMessage(m: String) extends UserMessage

class Test {

  type MessagePF = scala.PartialFunction[Message, String]
  type SysMessagePF = scala.PartialFunction[SysMessage, String]
  type UserMessagePF = scala.PartialFunction[UserMessage, String]

  def getSysMessage: SysMessagePF = {
    case sm: TextSysMessage ⇒ s"System message: ${sm.m}"
  }

  def getUserMessage: UserMessagePF = {
    case um: TextUserMessage ⇒ s"User message: ${um.m}"
  }

  def * : MessagePF = {
    case m ⇒ s"Unknown message: $m"
  }

  // Chained partials fails because `m` is a SysMessage with UserMessage
  def handler(m: Message): String = (getSysMessage orElse getUserMessage orElse *)(m)
}

显然,这种方法无法编译。我可以通过嵌套模式匹配来解决这个问题

def getSysMessage: MessagePF = {
  case m: SysMessage ⇒ m match {
    case sm: TextSysMessage ⇒ s"System message: ${sm.m}"
  }
}

然后我失去了处理catch中所有未知消息的能力。是否有一些优雅的方法来实现这一目标?

2 个答案:

答案 0 :(得分:4)

除了@adamwy + Hongxu Chen的回答,你可以定义你自己的组合器,它涉及隐式参数,因此强制执行稍微不同的应用程序语法

implicit class PartFuncOps[A: ClassTag, B](pf: PartialFunction[A, B]) {
  def or[D >: A, C <: D : ClassTag](other: PartialFunction[C, B]): PartialFunction[D, B] = {
    case a: A if pf.isDefinedAt(a) ⇒ pf(a)
    case c: C if other.isDefinedAt(c) ⇒ other(c)
  }
}

现在你可以写

def combine = getSysMessage or getUserMessage or *
def handler(m: Message): String = combine(m)

def handler(m: Message): String = (getSysMessage or getUserMessage or *).apply(m)

答案 1 :(得分:3)

根据@adamwy的建议,您可以将部分功能类型更改为:

Apparent symbolic reference i not allowed. 
WARNING: Apparent symbolic reference VALUE not resolved.
WARNING: Apparent symbolic reference I not resolved.
ERROR 22-322: Syntax error, expecting one of the following:
          a name, a quoted string, a numeric constant,
          a datetime constant, a missing value, INPUT,
          PUT.