前へ 目次 次へ
マニュアルばかり読んでいても始まらないので、なにか cabal-install のコード解析に結びつくものはないかと考えた。 cabal-install で import される大量のモジュールは Distribution ではじまるモジュールツリーの Cabal パッケージのライブラリが多い。これらのライブラリのソースを効率よく検索する方法はないかと思って探したらあった。 The Haskell Platform の ホームページの Documentation のページの Libraries だ。 Libraries のメイン・ウィンドウの左側にはツリー形式の Haskell Platform のライブラリのモジュール名が表示されている。また、右側にはそれらのモジュールが含まれるパッケージ名が表示されている。これを見ると Cabal のモジュール群は Distribution 以下のツリーにあり、その右側を見ると Cabal パッケージのバージョンは 1.16.0 であることが分かる。 Cabal のバージョン番号と cabal-install のバージョン番号は同じなので、cabal-install-1.16.0 のソースを入手すれば、cabal-install のコードを解析するのに、この Haddock が利用できることが分かる。 そこで The cabal-install package のページから cabal-install-1.16.0.tar.gz をダウンロードした。圧縮ファイルを解凍してできたディレクトリ cabal-install-1.16.0 に移動して、Main.hs ファイルを読んでみると、main 関数は、 main :: IO () main = getArgs >>= mainWorker となって、コマンドライン引数のリストを mainWorker 関数に引き渡しているだけだ。さいわい mainWorker 関数の定義は main 関数の定義のすぐ下にある。 mainWorker :: [String] -> IO () mainWorker ("win32selfupgrade":args) = win32SelfUpgradeAction args mainWorker args = topHandler $ ... mainWorker 関数の詳細に入る前に気になったのは topHandler という関数だ。mainWorker のコードの中でいろいろな処理がされた後の値が最終的に topHandler 関数に渡されている。いったい、topHandler とはどこに記述され、どのような機能があるのだろうか。 Main.hs 関数の冒頭の import 部分を見ると import Distribution.Simple.Utils ( cabalVersion, die, topHandler, intercalate ) となっているので topHandler が Cabal の Distribution.Simple.Utils モジュールの関数である事が分かる。それで先ほどの Libraries ツリーの Distribution.Simple.Utils をクリックするとこのモジュールの Haddock で作成されたこのモジュールの文書のHTML文書が表示される。 topHandler は Distribution.Simple.Utils の logging and errors セクションに記載されており、その型は次のようになる。 topHandler :: IO a -> IO a これをみると topHandler が IO モナドをアクションを引数にとり、IO モナドのアクションを返す事が分かるが、具体的な動作は分からない。そこで、上の関数の型宣言と同じ行にある Source リンクをクリックすると topHandler のソースを表示できる。その冒頭部分は次のようになる。 topHandler :: IO a -> IO a topHandler prog = catchIO prog handle where handle ioe = do catchIO 関数があるので引数 prog には IO モナドのアクションをとり、アクションにエラーが発生したときに handle 部分が実行されるはずだ。 handle 関数は where 以下で定義されているので、あまり外部の情報を必要としないだろう。エラー処理については topHandler 関数の内部に処理が内在していると思われる。したがって、prog に適当な IO アクションを割り当てる事で topHandler 関数をテストすることができると思われる。 そこで、ghci で topHandler 関数を試してみる事にした。まず必要なモジュールをインポートする。Distribution.Simple.Utils モジュールには topHandler 関数がある。System.IO をインポートしたのは hPutStr を利用してエラーを発生する IO モナドのアクションを作るためだ。 Prelude> import Distribution.Simple.Utils Prelude Distribution.Simple.Utils> import System.IO それでは、エラーを発生しないアクションについて topHandler がどのように振る舞うかを見てみよう。putStrLn "hello" はエラーを発生せず、値は IO () だ。このばあい単に putStrLn "hello" が実行される。 Prelude Distribution.Simple.Utils System.IO> topHandler (putStrLn "hello") hello そこでエラーを発生するアクションを作ってみる。hPutStr のハンドルに stdin を指定すると stdin には書き込めないのでエラーが発生するはずだ。 Prelude Distribution.Simple.Utils System.IO> hPutStr stdin "hello" *** Exception: このエラーを発生するアクションを topHandler に渡してみると、上のエラーの場合とは違ったフォーマットのエラーメッセージが表示された。 Prelude Distribution.Simple.Utils System.IO> topHandler (hPutStr stdin "hello") <interactive>: <stdin>: illegal operation *** Exception: ExitFailure 1 topHandler prog = catchIO prog handle の handle はエラーメッセージをフォーマットして表示する関数だった。そのつもりで topHandler の全ソースを読むと、その動作がどうプログラムされているかがよくわかる。 topHandler :: IO a -> IO a topHandler prog = catchIO prog handle where handle ioe = do hFlush stdout pname <- getProgName hPutStr stderr (mesage pname) exitWith (ExitFailure 1) where mesage pname = wrapText (pname ++ ": " ++ file ++ detail) file = case ioeGetFileName ioe of Nothing -> "" Just path -> path ++ location ++ ": " #if defined(__HUGS__) || (defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ < 608) location = "" #else location = case ioeGetLocation ioe of l@(n:_) | n >= '0' && n <= '9' -> ':' : l _ -> "" #endif detail = ioeGetErrorString ioe そんなに長い関数ではない。Haskell のプログラムはモジュール化されているので長大な一本コードというものはあまりないようだ。また、関数型の特性から topHandler 関数のように部分的なコードをテストすることができる。cabal-install にインポートされた大量のモジュールをみると怖じ気がつくが、Haddock を使えばかなり効率的にソースを解析できそうだ。 付録 getProgName :: IO String は System.Environment モジュールの関数。プログラム名を取得する。 Prelude> import System.Environment Prelude System.Environment> getProgName "<interactive>" exitWith :: ExitCode -> IO a 関数はプログラムを終了させ ExitCode を返す。System.Exit モジュールの関数。ExitCode のコンストラクタは次の2つ。 ExitSuccess ExitFailure Int Prelude> import System.Exit Prelude System.Exit> exitWith ExitSuccess *** Exception: ExitSuccess 目次 次へ
by tnomura9
| 2013-10-23 00:56
| Haskell
|
Comments(0)
|
カテゴリ
新型コロナウイルス 主インデックス Haskell 記事リスト 圏論記事リスト 考えるということのリスト 考えるということ ラッセルのパラドックス Haskell Prelude Ocaml ボーカロイド 圏論 jQuery デモ HTML Python ツールボックス XAMPP Ruby ubuntu WordPress 脳の話 話のネタ リンク 幸福論 キリスト教 心の話 メモ 電子カルテ Dojo JavaScript C# NetWalker ed と sed HTML Raspberry Pi C 言語 命題論理 以前の記事
最新のトラックバック
最新のコメント
ファン
記事ランキング
ブログジャンル
画像一覧
|
ファン申請 |
||