Haskellでgrep

30分プログラム、その386。Haskellgrepを作ってみた。

最初、grep関数はこんな感じに書いてた。

grep r lines = let regex = mkRegex r in
               filter (containRegex regex) lines

で、いちど動いたあとに、どんどん引数を消していったら以下のようになった。

grep = filter . containRegex . mkRegex

こうやって引数をどんどん消していくのは、なかなかに楽しい。Perlの$_やコンテキストを使って、コードを短くしていくのと同質の快感を感じる。
これをさらに追求していくと、ゴルファーになれるんだろうな、たぶん。とりあえず、ボクはしばらくゴルファーにならなくてもいいや。

使い方

# grep
$ ./grep Haskell diary.txt
*amicable*[Haskell][30分プログラム]Problem21 -友愛数の和-
*diag*[Haskell][30分プログラム]Problem28
*euler*[Haskell][30分プログラム]Problem32
...

# 正規表現も使える
$ ./grep '\*{2} ' diary.txt
** 1 実数の絶対値
** 2 立方根
** 3 二分法
** 6 状態不変表明
...

ソースコード

import Text.Regex
import System
import System.IO

-- cf. http://d.hatena.ne.jp/mzp/20080930/argf
argf :: [String] -> (String -> IO ()) -> IO ()
argf args f = case args of
                [] ->
                    getContents >>= f
                _ ->
                    mapM readFile args >>= f . concat

containRegex :: Regex -> String -> Bool
containRegex regex str = matchRegex regex str /= Nothing

grep :: String -> [String] -> [String]
grep = filter . containRegex . mkRegex

main = do (regex:args) <- getArgs
          argf args (putStrLn . unlines . grep regex . lines)
          return ()