é¢æ°åãã¼ãµã¼
ãããã Haskell ã®æ¬ãåºçãããã®ã§å¾©ç¿ããã
ãããã°ã©ãã³ã° Haskellã ã®ç¬¬8ç« ãä»å㯠Scala(version 2.9.2) ã§æ¸ãã
Scala çã«ä½¿ã£ãæ¹ããããããã®ã§ Option ã Either ãåå¼·ããã
Scala ã® API ã¨ä»¥ä¸ãåèã«ããªããæ¸ãã¦ã¿ãã
- Java で Either モナド - xuwei-k's blog
- Modegramming Style: Scala Tips / Option - Index
- Modegramming Style: Scala Tips / Either - Index
ã¾ãã¯ãã¿ã¼ã³ãããã§
ã»ã¨ãã©å¤ãããªãã¯ãã ããæ¸ç±ããã Code ã® Parsing.lhs 㨠parser.lhs ã®æ¹ãåèã«ããã
object Parsers { type P[A] = Seq[Char] => Option[(A,Seq[Char])] implicit def parserWrapper[A](p: P[A]) = new { def >>=[B](f: A => P[B]): P[B] = inp => parse(p, inp) match { case None => None case Some((v,out)) => parse(f(v), out) } def +++(q: P[A]): P[A] = inp => parse(p, inp) match { case None => parse(q, inp) case x => x } } def parse[A](p: P[A], inp: Seq[Char]): Option[(A,Seq[Char])] = p(inp) def unit [A](v: A): P[A] = inp => Some((v,inp)) def failure[A] : P[A] = inp => None def item : P[Char] = inp => inp match { case Seq() => None case Seq(v,out@_*) => Some((v,out)) } def many [A](p: P[A]): P[Seq[A]] = many1(p) +++ unit(Seq.empty) def many1[A](p: P[A]): P[Seq[A]] = p >>= (v => many(p) >>= (vs => unit(v+:vs))) def token[A](p: P[A]): P[A] = space >>= (_ => p >>= (v => space >>= (_ => unit(v)))) val sat: (Char => Boolean) => P[Char] = p => item >>= (x => if (p(x)) unit(x) else failure) val digit = sat(_.isDigit) val lower = sat(_.isLower) val upper = sat(_.isUpper) val alpha = sat(_.isLetter) val alphanum = sat(_.isLetterOrDigit) val char: Char => P[Char] = x => sat(_ == x) val string: String => P[String] = { case "" => unit("") case x => char(x.head) >>= (_ => string(x.tail) >>= (_ => unit(x))) } val ident = lower >>= (x => many(alphanum) >>= (xs => unit(x+:xs))) val nat = many1(digit) >>= (xs => unit(xs.mkString.toInt)) val int = (char('-') >>= (_ => nat >>= (n => unit(-n)))) +++ nat val space = many(sat(_.isWhitespace)) >>= (_ => unit()) val identifier = token(ident) val natural = token(nat) val integer = token(int) val symbol: (String => P[String]) = xs => token(string(xs)) } import Parsers._ lazy val expr: P[Int] = term >>= (t => (symbol("+") >>= (_ => expr >>= (e => unit(t+e))) ) +++ unit(t)) lazy val term: P[Int] = fact >>= (f => (symbol("*") >>= (_ => term >>= (t => unit(f*t))) ) +++ unit(f)) lazy val fact: P[Int] = (symbol("(") >>= (_ => expr >>= (e => symbol(")") >>= (_ => unit(e)))) ) +++ natural val eval = (xs: String) => parse(expr, xs.toSeq) match { case Some((n, Seq())) => n case Some((_, out)) => sys.error("unused input " + out.mkString) case None => sys.error("invalid input") } assert( eval("2*3+4") == 10 ) assert( eval("2*(3+4)") == 14 ) assert( eval("2 * (3 + 4)") == 14 )
Option ã®ã¡ã½ããã使ã
ãã¿ã¼ã³ãããã¯ä¸è¦§æ§ã«ããããã®ã ããã©ã Option ã§ãã¿ã¼ã³ãããããå ´åã«æ±ºã¾ã£ãå½¢ãç¾ããã
ãã®é¨åã® None => None ã¯ä½åº¦ãæ¸ãã¦ããã¨é£½ãã¦ãã...å¤å
def >>=[B](f: A => P[B]): P[B] = inp => parse(p, inp) match { case None => None case Some((v,out)) => parse(f(v), out) }
ã¨ããããã§çç¥ãã¦ãã¾ãã
def >>=[B](f: A => P[B]): P[B] = inp => parse(p, inp).flatMap{ case (v,out) => parse(f(v), out) }
Some ãæ¸ããªã代ããã« flatMap ã§ã¤ãªããã ãã
ããä¸ã¤ã®æ¹ã x => x 㯠Some(y) => Some(y) ãªã®ã§ä½ãã¡ã½ãããããããã
def +++(q: P[A]): P[A] = inp => parse(p, inp) match { case None => parse(q, inp) case x => x }
ããããOption ã® API ãæ¢ãã¦ã¿ããããã¨æãããã®ããªãã£ãã
def +++(q: P[A]) : P[A] =
inp => parse(p, inp).toLeft(parse[A](q, inp)).fold(Option(_), identity)
toLeft ã§ä¸æ¦ Either ã«å¤æãã¦å度 fold 㧠Option ã«æ»ãã¦ããã
ãããã None => None ã®å ´å㯠flatMap ã§æ¸ãã®ã§ã¡ã½ããã«ããã°ãããã
ãã以å¤ã®å ´åã¯æåãã Either ã使ãã®ã ããã
Either ã®ã¡ã½ããã使ã
ãã¼ãµã¼ã®æ»ãå¤ã Either åã«å¤æ´ããã
ã¾ãã¯ãã¿ã¼ã³ãããã§
type P[A] = Seq[Char] => Either[Unit,(A,Seq[Char])] implicit def parserWrapper[A](p: P[A]) = new { def >>=[B](f: A => P[B]): P[B] = inp => parse(p, inp) match { case Left(_) => Left() case Right((v,out)) => parse(f(v), out) } def +++(q: P[A]): P[A] = inp => parse(p, inp) match { case Left(_) => parse(q, inp) case x => x }
None ã Left ã«ãSome ã Right ã«å¤ãã£ãã ã
ããã Either ã®ã¡ã½ããã使ãããã«å¤æ´ãã¦ã¿ãã
implicit def parserWrapper[A](p: P[A]) = new { def >>=[B](f: A => P[B]): P[B] = inp => parse(p, inp).right flatMap{ case (v,out) => parse(f(v), out) } def +++ (q: P[A]) : P[A] = inp => parse(p, inp).left flatMap{ case _ => parse(q, inp) } }
両æ¹ã¨ã flatMap ã«ãªãã®ã§èªã¿ãããã
.right ã .left 㯠ãRight ã ã£ãããããLeft ã ã£ãããã¨èªããã
ãã¼ãµã¼ãçæãã¦ããé¨åãå¤æ´ããªãã¦ã¯ãªããªãã
ãããç´ ç´ã« None ã Left ã« Some ã Right ã«æ¸ãæããã ãã
def unit [A](v: A): P[A] = inp => Right((v,inp)) def failure[A] : P[A] = inp => Left() def item : P[Char] = inp => inp match { case Seq() => Left() case Seq(v,out@_*) => Right((v,out)) }
item 㯠Seq ã§ãã¿ã¼ã³ããããã¦ãããããããã¿ã¼ã³ãããã§ãªãããã¨ãã§ããã
def item : P[Char] = inp => if (inp.isEmpty) Left() else Right((inp.head,inp.tail))
ããã« Either ã®ã¡ã½ããã使ã£ã¦
def item : P[Char] = inp => Either.cond(!inp.isEmpty, (inp.head,inp.tail), ())
å·¦ã Right ã§å³ã Left ãªã®ã§å°ããããããã
for å¼ã使ã
調ã¹ã¦ãããã第8ç« ã Scala ã§å®è£ ããã¦ããæ¹ãããã
- http://www.ayutaya.com/dev/scala/haskell-parser-generator
- http://svc.ayutaya.com/wordpress/2011/04/22/scala-haskell-parser-generato/
ãã¼ãµã¼ã« map 㨠flatMap ãå®è£
ããã¦ããã° for å¼ã使ãããããã
object Parsers { type P[A] = Seq[Char] => Either[Unit,(A,Seq[Char])] implicit def parserWrapper[A](p: P[A]) = new { def flatMap[B](f: A => P[B]): P[B] = inp => parse(p, inp).right flatMap{ case (v,out) => parse(f(v), out) } def map [B](f: A => B) : P[B] = inp => parse(p, inp).right flatMap{ case (v,out) => Right((f(v),out)) } def +++ (q: P[A]) : P[A] = inp => parse(p, inp).left flatMap{ case _ => parse(q, inp) } } def parse[A](p: P[A], inp: Seq[Char]) = p(inp) def unit [A](v: A): P[A] = inp => Right((v,inp)) def failure[A] : P[A] = inp => Left() def item : P[Char] = inp => Either.cond(!inp.isEmpty, (inp.head,inp.tail), ()) def many [A](p: P[A]): P[Seq[A]] = many1(p) +++ unit(Seq.empty) def many1[A](p: P[A]): P[Seq[A]] = for (v <- p; vs <- many(p)) yield v+:vs def token[A](p: P[A]): P[A] = for (_ <- space; v <- p;_ <- space) yield v val sat: (Char => Boolean) => P[Char] = p => for (x <- item; y <- if (p(x)) unit(x) else failure) yield(y) val digit = sat(_.isDigit) val lower = sat(_.isLower) val upper = sat(_.isUpper) val alpha = sat(_.isLetter) val alphanum = sat(_.isLetterOrDigit) val char: Char => P[Char] = x => sat(_ == x) val string: String => P[String] = { case "" => unit("") case x => for (_ <- char(x.head);_ <- string(x.tail)) yield x } val ident = for (x <- lower; xs <- many(alphanum)) yield x+:xs val nat = for (xs <- many1(digit)) yield xs.mkString.toInt val int = (for (_ <- char('-'); n <- nat) yield -n) +++ nat val space = for (_ <- many(sat(_.isWhitespace))) yield () val identifier = token(ident) val natural = token(nat) val integer = token(int) val symbol: (String => P[String]) = xs => token(string(xs)) } import Parsers._ lazy val expr: P[Int] = for { t <- term r <- (for { _ <- symbol("+"); e <- expr } yield t+e) +++ unit(t) } yield r lazy val term: P[Int] = for { f <- fact r <- (for { _ <- symbol("*"); t <- term } yield f*t) +++ unit(f) } yield r lazy val fact: P[Int] = (for { _ <- symbol("(") e <- expr _ <- symbol(")") } yield e) +++ natural val eval = (xs: String) => parse(expr, xs.toSeq) match { case Right((n, Seq())) => n case Right((_, out)) => sys.error("unused input " + out.mkString) case Left(_) => sys.error("invalid input") } assert( eval ("2*3+4") == 10 ) assert( eval ("2*(3+4)") == 14 ) assert( eval ("2 * (3 + 4)") == 14 )
flatMap ã ãã§ããããã«æãã map ããªãã¨ã¨ã©ã¼ã«ãªãã
eval ã§ã¡ã½ãã使ã£ã¦ãªããã¨ã«æ°ã¥ããããããã¯ãã¿ã¼ã³ãããã®æ¹ãè¦ãããã®ã§ãã®ã¾ã¾ã«ãã¦ããã