0

Parsec を学習する中で、次のようなやや冗長なルールがあることがわかりました。

type PhonemeClassMap = Map Char String
type ContextElement = Parser String

phonemeContext :: Parsec String PhonemeClassMap ContextElement
phonemeContext = do
    c <- lower
    return $ char c

/モナドcharのような関数を持ち上げることで単純化できます。ParsecParsecT

phonemeContext :: Parsec String PhonemeClassMap ContextElement
phonemeContext = liftM char lower

今、ユーザーの状態を変更するルールを単純化しようとしています:

import Data.Map (insert)

phonemeClassDefinition :: Parsec String PhonemeClassMap ()
phonemeClassDefinition = do
    upperChar <- upper
    lowerChars <- char ':' >> spaces >> many1 lower
    modifyState (insert upperChar lowerChars)

簡単に持ち上げinsert :: Char -> String -> PhonemeClassMap -> PhonemeClassMapて、次の改善を行うことができます。

phonemeClassDefinition = do
    f <- liftM2 insert upper (char ':' >> spaces >> many1 lower)
    modifyState f

この 2 つの式を 1 つにまとめる方法はありますか? 同じリフティング テクニックは には機能しませんmodifyState :: Monad m -> (u -> u) -> ParsecT s u m ()

4

2 に答える 2

3

この場合、ピュアを取り、モナドアクションをモナドに返す>>= :: Monad m => (a -> m b) -> m a -> m b関数を適用できるようにするモナドバインドを探しています(つまり、モナドを「介して」関数を適用します)。この関数は実際にはモナド型クラスの不可欠な部分であり、in記法がフードの下で desugar するものです。aa<-do

liftM2(ちなみに、 、 ...とは異なり、便宜上、定義済み(またはetc)liftM3はないようです。( Hoogle は空白を描画します。))bindM2 :: Monad m => (a -> b -> m c) -> m a -> m b -> m cbindM3

また、Parsec パーサーは、その Applicative および Functor インスタンス、具体的には ( /<$>のエイリアス) だけでなく、モナドの& : &のさまざまな (半) 同等物を使用することで (スタイル上およびその他の点で) 恩恵を受けることがよくあります。fmapliftMap>><*><**>

phonemeContext = char <$> lower

phonemeClassDefinition = (insert <$> upper <*> (char ':' *> spaces *> many1 lower)) >>= modifyState

(@melpomene の=<<ものは単にflip (>>=)、つまり引数が入れ替わっていることに注意してください。)

于 2012-12-14T21:20:21.413 に答える
2
modifyState =<< liftM2 insert upper (char ':' >> spaces >> many1 lower)
于 2012-12-14T17:44:24.937 に答える