Python で簡単なテキスト処理 (2) - データの抽出 で行なった処理と同じものを Haskell でも書いてみる。前提となる知識は、
ただし、今回、正規表現は使わなかった。 (cf. Haskell で正規表現)
コードを以下に示す。
import qualified System.IO.UTF8 as U main = do cs <- U.getContents U.putStrLn $ unlines $ map extract $ filter match $ lines cs match :: String -> Bool match line = if (length $ words line) > 1 then True else False extract :: String -> String extract line = ds !! 0 ++ "\t" ++ ds !! 5 where ds = words line
慣れていないため手間取った。 ^^; どうしても Ruby や Python のように、ファイルから一行ずつ読み込み、それが対象の行か判断して、必要な部分を順次抽出するのを繰り返すというイメージから抜けだせなかった。 (@_@;)
上記の場合、 最初 lines によって行ごとの文字列のリストに変換し、それに対して filter 関数で必要な行だけを抽出し、更にそれに対して map 関数で必要なデータ列のみに変換する。そして、最後、全体を文字列として出力するため unlines で元の文字列に戻す。
頭のなかのイメージとしては、いつでもリスト全体に対して関数を適用した結果どうなり、それに対し更に関数を適用したらどうなるかというイメージをした。それに加え、適用する関数が全体から見て、どういったレベルを対象としているのか考える。例えば、 map, filter であれば、リストの各要素が対象となり、この場合なら、行ごとの処理を意味する。また、それらの関数に渡す関数は要素に対する処理、つまり、行を対象とすることになる。そして、それらの処理を連結していく。これが最初なかなかイメージしずらかった。 ^^;
考え直し
上記を書いた後、釈然としなかったので、もう一度考えなおすことに。何がしっくりこなかったかと言えば、先ほどのコードを書いているとき、思考の過程がボトムアップだったように思える。どういうことかと言えば、「今データがこうなっており、関数を適用するとそれがああなり、それに対してこうすればいいのか」というように、順を追ってデータの処理を考えたという感じ。今度は処理の内容を順次考えるのではなく、トップダウン的に考えることにする。つまり、「こうなって欲しい」、そして、こうなるためには「ああなって欲しい」というに。また、「こうなるためには、こういった型の値を渡すと、こういう型が返ってきて...」というに考えてみる。具体的には、最初に関数名を書き、次にそれがどんな引数を取り、そしてどんな型を返さなくてはいけないか型宣言を考えてから、実装に移る。
そうすると、さっきよりも長くなってしまったが、書きやすかったように思えるが気のせいだろうか。 (?_?)
import qualified System.IO.UTF8 as U main = do cs <- U.getContents U.putStrLn $ extract cs extract :: String -> String extract cs = unlines $ extractCol $ extractRow $ lines cs extractRow :: [String] -> [String] extractRow line = filter match line where match line = if (length $ words line) > 1 then True else False extractCol :: [String] -> [String] extractCol css = map extractData css where extractData line = ds !! 0 ++ "\t" ++ ds !! 5 where ds = words line
どういう風に考えていったかと言うと、まず getContents によって得た全体を extract 関数 で抽出して、putStrLn で出力すると考える。そうすると、extract 関数は String を引数に取り、 putStrLn が出力できるように String を返さなくてはいけない。ここではじめて lines – unlines のコンビネーションが必要で、その中では、行の抽出 (extractRow) と列の抽出 (extractCol) が必要であることがわかる。そして、extractRow, extractCol は文字列のリストを渡すと、文字列のリストを返すものだと想定する。そして、それぞれ実装がどうなるかを考えていくという思考の流れ。
うーん、こういう感じでいいのかなぁ~ (@_@;)
0コメント:
コメントを投稿