ふつける 4 章
ふつけるの 4 章。echo コマンド。
import System main = do args <- getArgs putStrLn $ unwords args
import は open みたいなものか。getArgs はコマンドライン引数を得るアクション。これがアクションになっているのは面白い。OCaml で書くと
open Sys let unwords = String.concat " " let _ = print_endline (unwords (List.tl (Array.to_list argv)))
Sys.argv は C と同じく先頭に自分自身のコマンド名が入っているため、取り除く必要がある。また、なぜか list ではなく array なので String.concat を使うためには Array.to_list でリストにしなければならない。
次は fgrep コマンド。
import System import List main = do args <- getArgs cs <- getContents putStr $ fgrep (head args) cs fgrep :: String -> String -> String fgrep pattern cs = unlines $ filter match $ lines cs where match :: String -> Bool match line = any prefixp $ tails line prefixp :: String -> Bool prefixp line = pattern `isPrefixOf` line
ちょっと複雑。まず目につくのは where 節。これいいよなあ。OCaml にかなり欲しい。
fgrep 関数はまず入力を行で区切って、そしてマッチする行のみを取り出して文字列にする。where 節の中の match 関数は、まず tails 関数で n 文字の文字列に対して 1 文字目から n 文字目、2 文字目から n 文字目… n 文字目から n 文字目、そして空文字列を含むリストを作る。つまり、tails "hoge" は
[ "hoge", "oge", "ge", "e", "" ]
となるらしい。そして、pattern がそのいずれかのプレフィックスとなっていればマッチが成功したとみなし、True が返される。どのプレフィックスにもなっていなければ False となる。この match 関数を filter に渡せば pattern を含む行を抜き出すことができる。
filter 関数は OCaml の List.filter と同じ。List.tails は OCaml には無さそう。定義するとしたら
let tails ls = let f elt tls = (elt::(List.hd tls))::tls in List.fold_right f ls [[]]
ぐらいか。ううむ。なんか遅そう。
any は List.exists と一緒。List.isPrefixOf は ML には無さそう。だけど SML には String.isPrefix という関数があった。
関数を `` で囲むと二項演算子のように使えるらしい。どうしても必要な機能ということでもないと思うが面白い。OCaml にはこのような機能はないが、同じことをするトリッキーな方法を見付けた。 Simple idea for making a function infix によると
によると、
let ( /* ) x y = y x and ( */ ) x y = x y
と定義して、
"HOGE" /* String.contains */ 'O'
のように使える。すげえ。よくこんなの思い付くなあ。