2

私は次のものを持っています、それはタイプチェックです:

p_int = liftA read (many (char ' ') *> many1 digit <* many (char ' '))

さて、関数名が示すように、私はそれが私にIntを与えることを望みます。しかし、私がこれを行う場合:

p_int = liftA read (many (char ' ') *> many1 digit <* many (char ' ')) :: Int

このタイプのエラーが発生します:

Couldn't match expected type `Int' with actual type `f0 b0'
In the return type of a call of `liftA'
In the expression:
    liftA read (many (char ' ') *> many1 digit <* many (char ' ')) ::
      Int
In an equation for `p_int':
    p_int
      = liftA read (many (char ' ') *> many1 digit <* many (char ' ')) ::
          Int

空白を含む可能性のある整数を解析するためのより簡単でクリーンな方法はありますか?またはこれを修正する方法は?

最終的に、これを次の一部にしたいと思います。

betaLine = string "BETA " *> p_int <*> p_int  <*> p_int <*>
           p_int <*> p_parallel <*> p_exposure <* eol

これは、次のような行を解析することです。

BETA  6 11 5 24 -1 oiiio

したがって、最終的には、これらの値を必要とするBetaPairコンストラクターを呼び出すことができます(一部はInt、一部は[Exposure]やParallelなどの他のタイプ)

(興味があれば、これは、とりわけ、タンパク質の水素結合したベータストランドペアを表すファイル形式のパーサーです。ファイル形式を制御することはできません!)

4

3 に答える 3

8

Parsecに電話させてもらうにはどうすればよいread :: Intですか?

2 番目の答えは、「read を使用しない」です。

使用readすることは、既に解析したデータを再解析することと同じです。そのため、Parsec パーサー内で使用することはコードの臭いです。自然数の解析は無害ですが、readParsec とは異なるエラー セマンティクスを持ち、Haskell の字句構文に合わせて調整されているため、より複雑な数値形式に使用するのは問題があります。

LanguageDefわざわざ a を定義して Parsec のモジュールを使用したくない場合Tokenは、read を使用しない自然数パーサーを次に示します。

-- | Needs @foldl'@ from Data.List and 
-- @digitToInt@ from Data.Char.
--
positiveNatural :: Stream s m Char => ParsecT s u m Int
positiveNatural = 
    foldl' (\a i -> a * 10 + digitToInt i) 0 <$> many1 digit
于 2012-05-23T19:45:25.243 に答える
5

p_intはを生成するパーサーであるIntため、タイプはParser Intまたは同様になります¹。

p_int = liftA read (many (char ' ') *> many1 digit <* many (char ' ')) :: Parser Int

readまたは、関数(read :: String -> Int)を入力して、式のタイプをコンパイラーに通知することもできます。

p_int = liftA (read :: String -> Int) (many (char ' ') *> many1 digit <* many (char ' ')) :: Int

よりクリーンな方法については、に置き換えることmany (char ' ')を検討してspacesください。

¹ ParsecT x y z Int、たとえば。

于 2012-05-23T18:55:26.993 に答える
1

あなたは見つけるかもしれません

Text-Megaparsec-Lexer.integer :: MonadParsec s m Char => m Integer

あなたが望むことをします。

バニラの parsec ライブラリには、多くの明白なパーサーが欠けているようで、「バッテリーを含む」parsec 派生パッケージの台頭につながっています。パーセクのメンテナーは、最終的にはより良いものを手に入れると思います。

https://hackage.haskell.org/package/megaparsec-4.2.0/docs/Text-Megaparsec-Lexer.html

アップデート

またはバニラパーセクで:

Prelude Text.Parsec Text.Parsec.Language Text.Parsec.Token> parse ( integer . makeTokenParser $ haskellStyle ) "integer" "-1234"
Right (-1234)
于 2015-11-22T04:28:45.840 に答える