既習のモナドを組み合わせると、パーサーもこんなふうになるというよい例だと思います。ただ、かなり複雑にはなってきていますが。 20170401のような日付のパーサーの例です。
data YMD = YMD Int Int Int deriving Show
countRead :: Read a => Int -> Parser Char -> Parser a
countRead i = fmap read . count i
ymdParser :: Parser YMD
ymdParser = YMD <$> countRead 4 digit <*> countRead 2 digit <*> countRead 2 digit
countRead :: Read a => Int -> Parser Char -> Parser a
countRead i = fmap read . count i
ymdParser :: Parser YMD
ymdParser = YMD <$> countRead 4 digit <*> countRead 2 digit <*> countRead 2 digit
1. YMD は関数:データコンストラクタ YMD は、単なる値ではなく
YMD :: Int -> Int -> Int -> YMD という「Intを3つ受け取って YMD を返す関数」でもある。
2. countRead の役割:countRead n digit は「数字を n 個読み取り、それを整数として解釈する」パーサーである。
例えば: countRead 4 digit :: Parser Int(年を読む)
countRead 2 digit :: Parser Int(月や日を読む)
3. <$> で最初の適用:(<$>) :: (a -> b) -> Parser a -> Parser b
a = Int b = Int -> Int -> YMD 関数 f = YMD 値 Parser a = countRead 4 digit
したがって: YMD <$> countRead 4 digit :: Parser (Int -> Int -> YMD)
ここで、Parser の中には「年をすでに受け取った部分適用関数 YMD y」が入っている。
4. <*> で次々に引数を渡す:次の <*> により
Parser (Int -> Int -> YMD) <*> Parser Int :: Parser (Int -> YMD)
さらにもう一度 <*> を使うと:
Parser (Int -> YMD) <*> Parser Int :: Parser YMD
※イメージ表せば
<$>:外の関数を箱に入れる <*>:箱の中の関数に箱の中の値を渡す
0 件のコメント:
コメントを投稿