2016-08-16 6 views
0

私はパーサーコンビネータについてのチュートリアルを読んでいて、理解しようとすると少し助けてくれる関数を見つけました。Haskell Parser Combinators - 文字列関数

let while_parser = string "while"

、その後、私は文字列は、たとえば言う解析するためにそれを使用:

satisfy :: (Char -> Bool) -> Parser Char 
satisfy p = item `bind` \c -> 
    if p c 
    then unit c 
    else (Parser (\cs -> [])) 

char :: Char -> Parser Char 
char c = satisfy (c ==) 

natural :: Parser Integer 
natural = read <$> some (satisfy isDigit) 

string :: String -> Parser String 
string [] = return [] 
string (c:cs) = do { char c; string cs; return (c:cs)} 

私の質問は、文字列関数の仕事をしたり、むしろそれが終了しないか、私のような何かをしたと言う方法です parse while_parser "while if"、それは正しく私に "while"を解析します。

しかし、parse while_parser "testのようなものを試してみると、[]が返されます。

私の質問はどのように失敗するのですか? char cが空のリストを返すとどうなりますか?

+0

私は 'char c'が"空のリストを返す "とは思っていませんが、入力の最後に*失敗*します。バインド演算子は、その失敗を伝播します。 – MathematicalOrchid

+0

あなたは 'let while_parser = string 'を意味していましたが、' '、そうですか? – sepp2k

+0

@MathematicalOrchid charが失敗したときにsatisfの定義から、空のリストを生成する関数を返します。伝播の失敗はどういう意味ですか? – Zubair

答えて

1

のはParserはこのように定義され、あなたの言ってみましょう:あなたはchar cは、この行に失敗したときに何が起こるか迷っている

instance Monad Parser where 
    return x = Parser $ \input -> [(x, input)] 
    p >>= f = Parser $ \input -> concatMap (\(x,s) -> runParser (f x) s) (runParser p input) 

newtype Parser a = Parser { runParser :: String -> [(a,String)] } 

次に、あなたのMonadインスタンスが定義されます。このような何かをコードの:

string (c:cs) = do { char c; string cs; return (c:cs) } 

Firs t、それをdesugarしましょう:

string (c:cs) = char c >>= \_ -> string cs >>= \_ -> return (c:cs) 

ここで興味のある部分はchar c >>= \_ -> string csです。 charの定義から、satisfyの定義から、最終的にrunParser (char c) inputは、char cが失敗した場合、[]と評価されることがわかります。 pchar cの場合、>>=の定義を見てください。 concatMapはリストが空であるために何の仕事もしません!したがって、その後の>>=への呼び出しは空のリストに遭遇し、それを一緒に渡します。

参照透過性についての素晴らしい点の1つは、定義を置き換えて機能アプリケーションを手作業で行うことによって表現を書き留めて評価できることです。

+0

技術的には、desugaringはモナドが使用されているものとは無関係なので、 'char c >> string cs >> return(c:cs)'にはなりません。 'm >> f'は通常は必須ではありませんが、' m >> = \ _-> f'として実装されます。 – chepner

+0

@chepnerはい。私は接線の詳細を説明するにはあまりにも怠惰でした。 – user2297560

+0

ありがとう、私はそれを得るのが一種だと思いますが、文字列への再帰呼び出しはどこにあるのですか? – Zubair