16.5 簡易URL解析
練習問題16.5.3 への回答.
URLの(ものすごく)適当なパーサ?を作ります.
コンビネータとかかっこいいことは何もなくて, 単に手書きでゴリゴリ書く問題です.
直前に出てきたreaderを使う練習でしょう.
以下のような形式の文法を解析します.
url ::= http://domain<path><anchor> | file://path | relativePath domain ::= id | id.domain path ::= /relativepath id ::= [a-zA-Z][a-zA-Z0-9]* anchor ::= #id
ホント適当ですね(^^
で,本文中でhttp形式のパーサ(笑)は与えられているので,
残っているfileとrelativepath(相対パス)形式のパーサを書くのが本題です.
回答
以下のようになりました.
structure SS = Substring; fun parseFile s = (* ファイルパス形式解析 *) let val s = if SS.isPrefix "://" s then SS.triml 3 s (* プレフィックス削除 *) else raise urlFormat val (relpath,anchor) = SS.splitl (curry op<> #"#") s (* 末尾のアンカーを分割 *) (* 文字列を '/' 区切りでトークンに分割 *) val xs = map SS.string $ SS.tokens (curry op= #"/") relpath val last_ = List.last xs in if SS.isEmpty anchor then {path=xs, anchor=NONE} else {path=xs, anchor=SOME $ SS.string $ SS.triml 1 anchor} end fun parseRelative s = (* 相対アドレス解析 *) let val (path,anchor) = SS.splitl (curry op<> #"#") s val xs = map SS.string $ SS.tokens (curry op= #"/") path in {path=xs, anchor=if SS.isEmpty anchor then NONE else SOME $ SS.string anchor} end
使用する様子
(* http形式 *) - Url.parseUrl "http://d.hatena.ne.jp/eldesh/edit#hoge"; val it = HTTP {anchor=SOME "hoge",host=["d","hatena","ne","jp"], path=SOME ["eldesh","edit"]} : Url.url (* ファイルパス形式 *) - Url.parseUrl "file://usr/local/bin/gcc"; val it = FILE {anchor=NONE,path=["usr","local","bin","gcc"]} : Url.url (* 相対パス形式 *) - Url.parseUrl "../../www/apache/httpd.conf"; val it = RELATIVE {anchor=NONE,path=["..","..","www","apache","httpd.conf"]} : Url.url
ファイルパスにアンカーとか要るのか分かりませんが, とりあえず動いてるようですね.
SubstringとString型を変換しながら処理するのはめんどくさいので,
出来るだけ文字列処理はSubstringで完結しておいて, 最後にStringに戻すべきかな.
というか違いがよく分からないけど,SubstringはStringPieceみたいなモンなのかな?
きれいなCurry化
ところでSMLについて喋ると必ず言ってますけど,
二項演算子が2タプルを引数に取るんですね. つまり…
- op+ 2 3 stdIn:6.1-6.8 Error: operator and operand don't agree [literal] operator domain: 'Z * 'Z operand: int in expression: + 2
引数を二つ並べるとエラーになりますorz
正しくはこう
- op+ (2,3) val it = 5 : int
つまりカリー化出来ないorz
コレを解決するために, この本の中のコードは
fun neq a b = not (a=b); fun eq a b = (a=b);
みたいな目も当てられない感じのことになってます.
私の回答中では以下の関数でしのいでいますが,
fun curry f x y = f (x,y);
それでも見づらいので何かカリー化するprefix記号を考えたいんですが思いつかない….いいもの有ったら教えて下さい.
カリー化っぽい記号って何だろう?