解析器上的~
方法將兩個解析器合併爲一個,它將連續應用兩個原始解析器並返回兩個結果。這可能是簡單的(在Parser[T]
)
def ~[U](q: =>Parser[U]): Parser[(T,U)].
如果你從來沒有合併兩個以上的解析器,這將是確定。但是,如果您將他們三人,p1
,p2
,p3
,與返回類型T1
,T2
,T3
,然後p1 ~ p2 ~ p3
,這意味着p1.~(p2).~(p3)
是Parser[((T1, T2), T3)]
類型。如果你結合其中的五個,如你的例子,那將是Parser[((((T1, T2), T3), T4), T5)]
。然後,當你對結果進行模式匹配時,你會得到所有這些缺口:
case ((((_, id), _), formals), _) => ...
這很不舒服。
然後來了一個聰明的語法技巧。當案例類有兩個參數時,它可以出現在中綴中,而不是模式中的前綴位置。也就是說,如果您有 case class X(a: A, b: B)
,則可以與case X(a, b)
進行模式匹配,但也可以使用case a X b
進行模式匹配。 (這是用x::xs
來匹配非空列表的做法,::
是一個案例類)。 當你編寫案例a ~ b ~ c
,這意味着case ~(~(a,b), c)
,但是也比case ((a,b), c)
更愉快,更愉快,這很難得到正確的。
因此,解析器中的~
方法返回Parser[~[T,U]]
而不是Parser[(T,U)]
,因此您可以輕鬆地對多個〜的結果進行模式匹配。除此之外,~[T,U]
和(T,U)
幾乎是相同的東西,因爲你可以得到同構。
爲解析器和結果類型中的組合方法選擇相同的名稱,因爲生成的代碼是自然可讀的。立即看到結果處理中的每個部分如何與語法規則的項目相關。
parser1 ~ parser2 ~ parser3 ^^ {case part1 ~ part2 ~ part3 => ...}
選擇Tilda是因爲它的優先級(它緊緊地綁定)與解析器上的其他運算符很好地配合。
最後一點,有輔助運算符~>
和<~
,它們丟棄操作數之一的結果,通常是規則中不攜帶有用數據的常量部分。所以人們寧願寫
"class" ~> ID <~ ")" ~ formals <~ ")"
並只得到在結果中的ID和形式的值。
非常感謝您的解釋。我對scala的「隱式轉換」功能並不熟悉。 關於該主題的一篇很好的文章可以在這裏找到:http://scalada.blogspot.com/2008/03/implicit-conversions-magical-and.html – Jano