2013-02-27 11 views
18

OKクラスのなかにApplicativeタイプのものが含まれていることがわかりました。しかし、私はあなたの脳を、あなたがそれを自明ではない例で使う方法の周りにかなり包み込むことはできません。今、一体あなたはParserためMonadインスタンスを使用せずにいることを書くでしょうかモナドからアプリケーションへの翻訳

integer :: Parser Integer 
integer = do 
    many1 space 
    ds <- many1 digit 
    return $ read ds 

は、例えば、以下のかなり単純なParsecのパーサを考えてみましょうか?たくさんの人がこれを行うことができ、良いアイデアだと主張していますが、どのように正確に把握することはできません。あなたはこれらのいずれかがより読みやすいと思いますかどうか

答えて

11
integer :: Parser Integer 
integer = read <$> (many1 space *> many1 digit) 

それとも

integer = const read <$> many1 space <*> many1 digit 

はあなた次第です。

+0

なぜ 'const'ですか? – MathematicalOrchid

+1

'many1 space'の値を無視しますが、' many1 space'の値に 'read'を適用します。 (すみません、私はちょうど入ってきました、遅いです、私は疲れています:私は速く、用語で緩んでいます) '' '' '' '' '' '' '' '' 'const read sd' =' read d'である場合には、const read <$> many1 space <*> many1 digitの値は無視されます。 – dave4420

38

私は(アプリケーションのように)左結合パーサ構築事業者<$><*><$<*の束があります

integer :: Parser Integer 
integer = read <$ many1 space <*> many1 digit 

記述します。一番左のものは、結果値をコンポーネント値からアセンブルする純粋な関数でなければなりません。各演算子の右側にあるものはパーサであり、集合的に左から右の文法のコンポーネントを与えます。どちらの演算子を使うかは、次の2つの選択肢によって決まります。

だから、
the thing to the right is signal/noise 
    _________________________    
    the thing to the left is \   
          +------------------- 
        pure/| <$>  <$ 
        a parser | <*>  <* 

、パーサのセマンティクスを提供するために起こっている、純粋な関数としてread :: String -> Integerを選択した、私たちは「信号」として、「ノイズ」と数字の束として、先頭のスペースを分類することができ、それゆえ

read <$ many1 space <*> many1 digit 
(..) (.........)  (.........) 
pure noise parser  | 
(.................)  | 
    parser    signal parser 
(.................................) 
        parser 

あなたは

p1 <|> ... <|> pn 

とエクスプレス不可能で複数の可能性を組み合わせることができます0

empty 

パーサーでコンポーネントの名前を付ける必要はほとんどなく、結果のコードはセマンティクスが追加された文法に似ています。

+8

うわー、私は '$ <$'について知っていましたが、その左側のものが定数で、右側が単純な値だったならば、これを使ったことはありません...私は関数左へ:Pニーストリック –

7

あなたの例では、徐々により明確Applicativeのに似た形に書き換えることができる:do表記の

do 
    many1 space 
    ds <- many1 digit 
    return $ read ds 
  1. 定義:$

    many1 space >> (many1 digit >>= \ds -> return $ read ds) 
    
  2. が定義:

    many1 space >> (many1 digit >>= \ds -> return (read ds)) 
    
  3. .

    定義:

    many1 space >> (many1 digit >>= (return . read)) 
    
  4. 3モナド則(連想):

    (many1 space >> many1 digit) >>= (return . read) 
    
  5. 定義liftMの(非do表記):

    liftM read (many1 space >> many1 digit) 
    

これはあなたの例と動作が同じです(または、私がうんざりしていない場合)。

さて、あなたは<$>fmapliftMを交換し、*>>>場合、あなたはApplicativeのを取得:

read <$> (many1 space *> many1 digit) 

これが原因liftMfmap、および<$>が一般的のように、同義語ことになっている有効です。 >>*>です。

これはすべて元々の例では、次のパーサーを構築するためにパーサの結果を使用していないため、これを行うことができます。

+0

クール! 'read <$ many1 space <*> many1 digit 'と書く別の方法です。 :)最後の文は非常に重要です。これは、このスタイルが文脈自由文法に対応し、より一般的な文法はモナド様式で解析されなければならないということですか? –

+0

@WillNess私はこれに関する専門家ではありませんが、私はそうであると信じています。 –