2013-06-22 75 views
4

我有一個monadic類型Exp,我想構建一個解析器來解析這樣的值。下面的代碼有效,但是我可以做些什麼更好/更酷的東西?將Monad包裝到解析器中 - 我是否需要Monad變形金剛以及如何操作?

def grid(x: Int, y: Int): Problem = ??? 
def expInt: Parser[Exp[Int]] = ??? 

def grid: Parser[Exp[Problem]] = 
    for{ 
    ex ~ _ ~ ey <- "grid(" ~> expInt ~ "," ~ expInt <~ ")" 
    } yield for{ 
    x <- ex 
    y <- ey 
    } yield grid(x,y) 

我聽說過單子變壓器,但仍然有點害怕斯卡拉茲7的奇怪的進口系統。有人能回答我是否

  1. 可以使用單子變壓器和
  2. 這將如何看起來像原理,採用Scalaz 7 Scala的組合符解析器包裝我自己Exp單子。
+0

問題是,在這種情況下,您希望從monad變壓器中獲得什麼好處? – drexin

+0

也許我不必寫第二個理解? – ziggystar

+0

啊,沒有看到它,對不起。 – drexin

回答

6

首先爲方便部分的 「怪異」 導入系統:

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(...)) 。

的這裏語法是醜陋的,我們失去了很好的~組合子和隱式轉換從StringParser[String],例如,但如果我們想,我們可以很容易地舉起寫這些東西的版本。

+0

所以有可能非常接近我的代碼,但沒有第二個「for」?我可能會在下週嘗試。 – ziggystar

+0

我目前正試圖實現monad變壓器。但不知何故,我在實現'flatMap'時遇到了麻煩。我還觀察到,在我的用例中,外部monad(Parser)僅用作函子(僅需要'map')。有可能我不能爲我的類型實現monad轉換器,但只能嵌套在一個函數中的某個函子? – ziggystar