2016-12-07 53 views
1

我正在尋找一種優雅的方式來鏈接從一個共同的基礎類型派生的部分功能。這個想法是,每個部分函數處理類型,使他們成爲很容易的出現了不同類型和有一個共同的包羅萬象的,如果鏈接的部分功能是不確定的:鏈接斯卡拉部分功能的優雅方式

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}" 
    } 
} 

但是然後我失去了處理未知消息的能力。有沒有一些優雅的方式來實現這一目標?

+4

爲什麼不用'Message'作爲輸入類型定義每個'PartialFunction'? – adamwy

+0

這基本上是計劃B .... –

+0

但你怎麼能期望一個部分函數,​​需要具體的子類型與任意'消息'工作?類似於'def handler(m:Message):String =(getSysMessage)(m)'也不起作用。 – adamwy

回答

2

至於除了@adamwy +楊紅旭陳的回答,您可以定義自己的組合子,它涉及隱含參數,所以強制執行略有不同的應用程序的語法

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) 
3

正如@adamwy建議,您可以更改部分功能類型爲:

type MessagePF = scala.PartialFunction[Message, String] 
type SysMessagePF = scala.PartialFunction[Message, String] 
type UserMessagePF = scala.PartialFunction[Message, String] 
+1

或者只是使用一種類型。 – adamwy