2014年2月14日金曜日

開発環境

Real World Haskell―実戦で学ぶ関数型言語プログラミング(Bryan O'Sullivan (著)、 John Goerzen (著)、 Don Stewart (著)、山下 伸夫 (翻訳)、伊東 勝利 (翻訳)、株式会社タイムインターメディア (翻訳)、オライリージャパン)の9章(入出力事例研究: ファイルシステム検索ライブラリ)、9.7(走査方法の制御)の練習問題 2.を解いてみる。

その他参考書籍

練習問題 2.

コード(BBEdit, Emacs)

ControlledVisit.hs

{-# OPTIONS -Wall -Werror #-}
module ControlledVisit where

import System.Directory (Permissions, getDirectoryContents, getPermissions,
                         getModificationTime, searchable)
import System.IO (IOMode(..), openFile, hClose, hFileSize)
-- System.Timeは非推奨
import Data.Time.Clock (UTCTime)
import System.FilePath ((</>))
import Control.Exception (handle, bracket, SomeException)
import Control.Monad (liftM, forM)

main :: IO ()
main = do
    infos1 <- traverse id "."
    infos2 <- traverse order1 "."
    putStrLn "行きがけ順(id)--------------------------------------"
    mapM_ print $ map infoPath infos1
    putStrLn "帰りがけ順(order1)---------------------------------"
    mapM_ putStrLn $ map infoPath infos2

data Info = Info { infoPath :: FilePath,
                   infoPerms :: Maybe Permissions,
                   infoSize :: Maybe Integer,
                   infoModTime :: Maybe UTCTime} deriving (Eq, Ord, Show)

getInfo :: FilePath -> IO Info
getInfo path = do
    perms <- maybeIO (getPermissions path)
    size <- maybeIO (bracket (openFile path ReadMode) hClose hFileSize)
    modified <- maybeIO (getModificationTime path)
    return (Info path perms size modified)

maybeIO :: IO a -> IO (Maybe a)
maybeIO act = handle nothing (Just `liftM` act)

nothing :: SomeException -> IO (Maybe a)
nothing _ = return Nothing

traverse :: ([Info] -> [Info]) -> FilePath -> IO [Info]
traverse order path = do
    names <- getUsefulContents path
    contents <- mapM getInfo (path:map (path </>) names)
    liftM concat $ forM (order contents) $ \info -> do
        if isDirectory info && infoPath info /= path
        then traverse order (infoPath info)
        else return [info]


getUsefulContents :: FilePath -> IO [String]
getUsefulContents path = do
    names <- getDirectoryContents path
    return (filter (`notElem` [".", ".."]) names)

isDirectory :: Info -> Bool
isDirectory = maybe False searchable . infoPerms

-- 帰りがけ順(子ディレクトリが親ディレクトリより先に返る)に操作する制御関数
order1 :: [Info] -> [Info]
order1 = foldr (\i acc -> if isDirectory i then acc ++ [i] else i:acc) []

入出力結果(Terminal, runghc)

$ runghc ControlledVisit.hs 
行きがけ順(id)--------------------------------------
"."
"./BetterPredicate.hs"
"./ControlledVisit.hs"
"./temp1_folder"
"./temp1_folder/temp11_folder"
"./temp1_folder/temp11_folder/temp111_folder"
"./temp1_folder/temp11_folder/temp112_folder"
"./temp1_folder/temp12_folder"
"./temp2_folder"
帰りがけ順(order1)---------------------------------
./BetterPredicate.hs
./ControlledVisit.hs
./temp2_folder
./temp1_folder/temp12_folder
./temp1_folder/temp11_folder/temp112_folder
./temp1_folder/temp11_folder/temp111_folder
./temp1_folder/temp11_folder
./temp1_folder
.
$

0 コメント:

コメントを投稿