IP adress with Parsec
Parsecを練習しなければ!
ということで
簡単なパーサーとして、
A.B.C.D
のようなIPアドレスから、数値のリスト、
[A,B,C,D]
を生成するパーサーを作ってみた
エラー処理も何もない、単純にドットを消していくだけのパーサです
import Text.ParserCombinators.Parsec num :: Parser Int num = many1 digit >>= return.read ipv4 :: Parser [Int] ipv4 = do a <- num b <- many (char '.' >> num >>= return ) return (a:b) main = parseTest ipv4 "255.128.64.10"
エラー処理などは含めていないけれど、
こんな感じで適当に書いたら出来てしまった。
なぜbが、この記述で[Int]になるのか不明.....
ドットを読み飛ばして値を読んで、その値を返すだけだから、
bの型もIntになりそうなのに
というわけで。
ghciですね
> :{ | let { f = do b <- many( | char '.' | >> num | >>= return) | return b | } | :}
として、fの型を調べると、やはり[Int]として出てきました。
そしてmanyの型を調べると、
many :: Text.Parsec.Prim.ParsecT s u m a -> Text.Parsec.Prim.ParsecT s u m [a]
と。
やはり、こいつがリストを生成してくれているんですね。
この関数が成功する間要素を作成したパーサに従い取り出し、リストにしてくれるわけだ。
なるほど!
そして、Applicativeモジュールを使って書きなおす
import Text.Parsec import Text.Parsec.String import Control.Applicative hiding (many) num' :: Parser Int num' = read <$> many1 digit ipv4 :: Parser [Int] ipv4 = (:) <$> num' <*> (many $char '.' >> num') main = parseTest ipv4 "255.128.64.10"
上のものより少しだけ短くなった!!
モジュール宣言が長くなってしまっているので関数部分だけ見ればなんと半分の量!
更に、読みやすくなった.....?笑
今までは
(>>=),(>>)などを使ってdoを消していたけれど、Applicativeを使えばreturnも消せる!!
これからもできるだけdo,returnは使わない形を目指したいと思います。
別に、それが悪いとか思ってるわけではないんですが、命令言語っぽく書けてしまうのはHaskellのスタイルとしてどうなんだろうと疑問に思ったりしています。