Haskellでいってみよう

日曜プログラマにも満たないレベルでもHaskellで何かソフトウェアを作りたい!

簡易cat (2)

ファイル内容を表示するだけでは寂しいので、コマンドラインに オプションを追加してみる。ややこしいのは大変なので、先頭に 行番号を表示する -n モドキだけ。

-n オプションがある場合は各行の表示をする時に番号を付加する。 行番号はいわゆる「無限リスト」を各行とzipで組にしてみた。

Cat4.hs
-- 
-- Cat4
-- 

module Main (
  main
) where

import System.Environment

main :: IO ()
main = do
  xs <- getArgs
  putFiles $ checkArgs xs

checkArgs :: [String] -> (Bool, [String])
checkArgs [] = (False, [])
checkArgs (x:xs)
  | x == "-n" = (True, xs)
  | otherwise = (False, (x:xs))

putFiles :: (Bool, [String]) -> IO ()
putFiles (_, []) = putStr ""
putFiles (b, (x:xs)) = do
  cs <- readFile x
  putStr (decorate b cs)
  putFiles (b, xs)

decorate :: Bool -> String -> String
decorate False cs = cs
decorate True cs = unlines $ map tr (zip [1..] $ lines cs)

tr :: (Int, String) -> String
tr (n, l) = (show n) ++ "\t" ++ l

単に最初の引数が"-n"かどうかをチェックしているだけなのに 結構邪魔くさいことになっている。 doブロック内でできることできないことについて、下記ではまった。

putFiles (b, (x:xs)) = do
  cs <- readFile x
  putStr (decorate b cs)

putStrのところ、今回は短いのでいいが、一旦変数にバインドしようとして 単に代入文を書いたらコンパイルエラーになった。

  cs' = decorate b cs
  putStr cs'

しょうがないのでputStr一行にまとめてしまったが、あとで試したらletを 使えば大丈夫そう。

  let cs' = decorate b cs
  putStr cs'

一方で where句ではエラーになった。csがスコープにないと怒られたので where句の中に"cs <- readFile x"を書いてもエラーになってしまう。

  putStr cs'
  where
    cs' = decorate b cs

letとwhereの違いを確認しておこう。

次回は使えそうなプログラムを作ってみる。