「Ansi Common Lisp」7章練習問題 - Haskell版
1. ファイル名を引数として、ファイルの各行を構成するストリングをリストとして返す関数を定義せよ。
うーん、相変わらずモナド分からん。。
近いものはできた。
import IO fileToStrLine :: String -> IO () fileToStrLine fileName = do handle <- openFile fileName ReadMode line <- hGetContents handle print . lines $ line hClose handle main = fileToStrLine "ex7-1.hs"
結果はこう。
["import IO","","fileToStrLine :: String -> IO ()","fileToStrLine fileName = do handle <- openFile \"ex7-1.hs\" ReadMode"," line <- hGetContents handle"," print . lines $ line"," hClose handle","","main = fileToStrLine \"ex7-1.hs\""]
3. コメントを%で示すようなテキストファイルのフォーマットがあるとする。この文字が出現した場合、その行のそれ以降の部分は全て無視される。2つのファイル名を引数とし、第2のファイルに第1のファイルのコメントを除外したコピーを作成する関数を定義せよ。
import IO import List import Maybe removePercentComment :: String -> String -> IO () removePercentComment inFile outFile = do inHandle <- openFile inFile ReadMode outHandle <- openFile outFile WriteMode cs <- hGetContents inHandle hPutStr outHandle $ unlines $ map removeAfterPercent $ lines cs hClose inHandle hClose outHandle removeAfterPercent :: String -> String removeAfterPercent str = if index == -1 then str else take index str where index = charIndex '%' str charIndex :: Char -> String -> Int charIndex c str = if index == Nothing then -1 else fromJust index where index = elemIndex c str main = removePercentComment "infile" "outfile"
IOモナドが分かってきたような、分かってないような。
(2008.08.28 追記)
コメント欄でtakeWhileを使ってはどうかとご指摘いただきましたので、
書き直してみました。
import IO import List import Maybe removePercentComment :: String -> String -> IO () removePercentComment inFile outFile = do inHandle <- openFile inFile ReadMode outHandle <- openFile outFile WriteMode cs <- hGetContents inHandle hPutStr outHandle $ unlines $ map (\str -> takeWhile (/='%') str) $ lines cs hClose inHandle hClose outHandle main = removePercentComment "infile" "outfile"
すっきり!
結果はこう。
taka@taka-desktop:~/lisp$ more infile abc % def %ghi %% jklmn opqrs% taka@taka-desktop:~/lisp$
taka@taka-desktop:~/lisp$ more outfile abc jklmn opqrs taka@taka-desktop:~/lisp$
どうでもいいが、Unixでファイルを見るときに使うコマンドで、
vi(view)派とmore(less)派がいるとかって話があったなあ。
僕は断然more派なんですが、まあきっとemacs派とかいろいろあるんでしょうね。
4. 浮動小数点数の2次元配列を引数として、桁をそろえて表示する関数を定義せよ。各要素は、小数点以下2桁を表示し、フィールドの幅は10字分とする。(全てこれで収まるものと仮定せよ。) 関数array-dimensions(配列を引数として、各次元の長さ(整数)をリストにして返す)が必要となるだろう。
import Text.Printf main = printFloatArray2d ([[1.234, 2.34], [3.4567, 4]] :: [[Float]]) printFloatArray2d :: [[Float]] -> IO a printFloatArray2d (x:[]) = printFloatArray x printFloatArray2d (x:xs) = do printFloatArray x printFloatArray2d xs printFloatArray :: [Float] -> IO a printFloatArray (x:[]) = printf "%10.2f\n" x printFloatArray (x:xs) = do printf "%10.2f " x printFloatArray xs
結果はこう。
1.23 2.34 3.46 4.00 *** Exception: Prelude.undefined
一応出来てるけど、なんかエラーも出てる。
http://itpro.nikkeibp.co.jp/article/COLUMN/20080630/309793/?ST=develop&P=2
に色々書いてあるけど、STモナドとか出てきてお腹いっぱい。。
ま、追々かな。