5

次のように、コンマで区切られた 2 つまたは 3 つの数値を処理できるパーサーを作成できます。

number :: Parser Int
number = many1 digit >>= return . read <?> "number"

numbers = do
  n1 <- number
  n2 <- char ':' >> number
  n3 <- optionMaybe $ char ':' >> number
  return ... -- return all of n1, n2, n3

数字だけが重要で、残りは破棄できます。n1,n2,n3外部で処理するために中間解析結果 ( ) を連結する方法はありinputますか? たとえば、Scala のパーサー コンビネーターは次のことができます。

def numbers: Parser[Int ~ Int ~ Option[Int]] = // only the important numbers are returned
  number ~ (":" ~> number) ~ opt(":" ~> number)

さまざまな場所でパーサーをパターン一致させるために、これを行いたいと考えています。たとえば、Scala では次のようなことができます。

val result = input.parseAs(numbers) {
  case n1 ~ n2 ~ None => // work with n1,n2
  case n1 ~ n2 ~ Some(n3) => // work with n1,n2,n3
}

ここで、入力は解析する文字列です。parsec には、同様の動作を可能にする組み込み関数がありますか? そうでない場合、自分でそのような動作を構築する方法はありますか?

4

1 に答える 1

8

アプリカティブ ファンクターを使用してそれを行うことができます。パターンは一般的に次のとおりです。

import Control.Applicative

f <$> a1 <*> a2 <*> a3

fこの場合、 は 3 つの引数を取る関数です。およびはa1、に引数として渡すことができる値に対する適用可能なファンクターです。ファンクターは順次適用され、その結果が収集され、関数にマップされます。a2a3ff :: Int -> Int -> Int -> Fooa1, a2, a3Parser Inta1, a2, a3f

あなたの場合、あなたはしたいでしょう:

numbers :: Parser (Int, Int, Maybe Int)
numbers =
  (,,)
  <$> number
  <*> (char ':' *> number)
  <*> optionMaybe (char ':' *> number)

(,,)は 3 タプルのコンストラクタなので、3 つの引数を取り、3 タプルを返す関数です。パターンで 3 つのパーサーを渡す<$>..<*>..と、3 タプル コンストラクターの適用が、ここで使用されているファンクターに持ち上げられます。Parserこの場合は、式全体がファンクターでラップされたマップされた関数の結果を返しますParser (Int, Int, Maybe Int)

;liftA3 f a1 a2 a3の代わりに使用することもできます。f <$> a1 <*> a2 <*> a32 つの式は同等です。

PS。アプリカティブ ファンクターを使用して定義することもできますnumber(モナド インターフェイスはより「重い」ので、個人的には避けようとしています)。

number :: Parser Int
number = read <$> many1 digit <?> "number"
于 2012-03-11T19:55:17.617 に答える