首先爲方便部分的 「怪異」 導入系統:
import scalaz._, Scalaz._
這就是全部。這將始終有效(當然,除了名稱衝突之外,這對任何圖書館都是一種可能性,並且很容易解決),並且沒有人會因爲不使用新的單點導入而忽視您,這些導入主要是關於文檔。
的單子變壓器的基本模式是,你必須有一個名爲runWhateverT
返回一個F[Whatever[...]]
的方法(或只是run
)一WhateverT[F[_], ...]
類型的類。
在這種情況下,它看起來像你想最後一個Parser[Exp]
,這表明你需要你自己的ExpT[F[_]]
變壓器。我不會跟有關如何實現這一點(這將取決於你的單子的語義,當然)細節入手,但會使用Scalaz的OptionT
舉個例子:
import scala.util.parsing.combinator._
import scalaz._, Scalaz._
object MyParser extends RegexParsers {
implicit val monad = parserMonad(this)
def oddNumber: OptionT[Parser, Int] = OptionT.optionT(
"\\d+".r ^^ (_.toInt) ^^ (i => (i % 2 != 0) option i)
)
def pairOfOdds: OptionT[Parser, (Int, Int)] = for {
_ <- literal("(").liftM[OptionT]
x <- oddNumber
_ <- literal(",").liftM[OptionT]
y <- oddNumber
_ <- literal(")").liftM[OptionT]
} yield (x, y)
def apply(s: String) = parse(pairOfOdds.run, s)
}
見my question here有關爲何一些討論我們需要implicit val monad = ...
一行。
它的工作原理是這樣的:
scala> MyParser("(13, 43)")
res0: MyParser.ParseResult[Option[(Int, Int)]] = [1.9] parsed: Some((13,43))
scala> MyParser("(13, 42)")
res1: MyParser.ParseResult[Option[(Int, Int)]] = [1.8] parsed: None
注意oddNumber.run
會給我們一個Parser[Option[Int]]
將分析的數字串並返回一個Some(i)
(如果它們代表奇數)或None
(如果他們甚至)。
我們不是真的要打電話oddNumber.run
,不過,在這種情況下,事實是,我們正在使用一個單子轉換意味着我們可以組成oddNumber
在單一for
理解解除Parser
行動(在這裏literal(...)
) 。
的這裏語法是醜陋的,我們失去了很好的~
組合子和隱式轉換從String
到Parser[String]
,例如,但如果我們想,我們可以很容易地舉起寫這些東西的版本。
問題是,在這種情況下,您希望從monad變壓器中獲得什麼好處? – drexin
也許我不必寫第二個理解? – ziggystar
啊,沒有看到它,對不起。 – drexin