人気ブログランキング | 話題のタグを見る

How to write a Haskell program 2

前へ 目次 次へ

How to write a Haskell program の続き

管理人注: 以下の実習は Unix の操作が想定されているので、Mac OS で確かめた。しかし、Windows でもできるはずだ。

2 Structure of a simple project

Haskell project を作るときの基本的な構造は HNop が参考になる。これは最小限の Haskell プロジェクトだ。これには次のようなファイルが含まれる。このプロジェクトの名前は "haq" とすることにする。

  • Haq.hs --- メインの Haskell ソースファイル
  • haq.cabal --- cabal のビルドの description
  • Setup.hs --- ビルドスクリプト本体
  • _darcs --- リビジョンコントロール
  • README --- プログラムの情報
  • LICENSE --- ライセンス

もちろん、もっと複雑な構造も作る事ができる。たとえば、サブ・ディレクトリーや複数のモジュールをプロジェクトに含める事ができる。大きな Haskell プロジェクトの例については Structure of a Haskell project を見てほしい。

ここでは、上で述べた darcs と cabal を利用した最小構成の Haskell プログラムである "haq" をビルドしてインストールを行い、さらには配布するところまで実習してみる。

注: cabal init はこの手続きを自動化する事ができるが、その場合でも開発者はプロジェクトの構成のすべてを把握している必要がある。

それでは、単純な Haskell の実行ファイルを作るためのインフラを作成する手続きを一通り実行してみよう。

管理人注: 次の実習をするためには darcs をインストールしておく必要があるが、darcs のダウンロードページからダウンロードできる。

2.1 Create a directory

$ mkdir haq
$ cd haq

2.2 Write some Haskell source

次のプログラム Haq.hs を作成する。

$ cat Haq.hs
--
-- Copyright (c) 2006 Don Stewart - http://www.cse.unsw.edu.au/~dons/
-- GPL version 2 or later (see http;//www.gnu.org/copyleft/gpl.html)
--
import System.Environment

-- | 'main' runs the main program
main :: IO ()
main = getArgs >>= print . haqify . head

haqify s = "Haq! " ++ s

2.3 Stick it in version control

このソースファイルをバージョン・コントロールプログラムの管理下に置くために、darcs を使用する。このソースの保守者を特定するために最初に e-mail アドレスを入力する必要がある。


$ darcs init
$ darcs add Haq.hs
$ darcs record
Each patch is attributed to its author, usually by email address (for
example, `Fred Bloggs '). Darcs could not determine
your email address, so you will be prompted for it.

Your address will be stored in _darcs/prefs/author.
It will be used for all patches recorded in this repository.
If you move that file to ~/.darcs/author, it will be used for patches
you record in ALL repositories.
What is your email address? nobody@nobody.com
addfile ./Haq.hs
Shall I record this change? (1/2) [ynW...], or ? for more options: y
hunk ./Haq.hs 1
+--
+-- Copyright (c) 2006 Don Stewart - http://www.cse.unsw.edu.au/~dons/
+-- GPL version 2 or later (see http;//www.gnu.org/copyleft/gpl.html)
+--
+import System.Environment
+
+-- | 'main' runs the main program
+main :: IO ()
+main = getArgs >>= print . haqify . head
+
+haqify s = "Haq! " ++ s
+
Shall I record this change? (2/2) [ynW...], or ? for more options: y
What is the patch name? patch-131019
Do you want to add a long comment? [yn]n
Finished recording patch 'patch-131019'

haq ディレクトリのリストをとると、darcs のリビジョン・コントロールが始まっているのが分かる。

$ ls
Haq.hs_darcs

_darcs ディレクトリの中を見ると、リビジョン・コントロールのためのいろいろなファイルが作成されているのが分かる。

$ ls _darcs
format  index_invalid  prefs
hashed_inventory  inventories  pristine.hashed
index  patches  tentative_pristine

2.4 Add a build system

次には .cabal ファイルを作成して haq プロジェクトのビルドを行うための設定を記述する。

$ cat haq.cabal
Name: haq
Version: 0.0
Description: Super cool mega lambdas
License: GPL
License-file: LICENSE
Author: Don Stewart
Maintainer: nobody@nobody.com
Build-Type: Simple
Cabal-Version: >= 1.2

Executable haq
  Main-is: Haq.hs
  Build-Depends: base >= 3 && < 5

Haskell Platform 以外のパッケージを(たとえば、haskell98)を利用している場合は、上の description の Build-Depends: フィールドにそのパッケージ名ををコンマ区切りのリストで追加する必要がある。

次に、ビルドを行うための Setup.hs スクリプトを作成する。

$ cat Setup.hs
import Distribution.Simple
main = defaultMain

また、LICENSE ファイルと README ファイルを作成する。

$ cat LICENSE
HNOP is written by Ashley Yakeley.

Permission is hereby granted, free of charge, to any person obtaining this work (the "Work"), to deal in the Work without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Work, and to permit persons to whom the Work is furnished to do so.

THE WORK IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE WORK OR THE USE OR OTHER DEALINGS IN THE WORK.

$ cat README
This is the smallest darcs and cabalized Haskell project.

新たに追加した変更点を darcs に記録する。

$ darcs add haq.cabal Setup.hs LICENSE README
$ darcs record --all
What is the patch name? patch-131016-02
Do you want to add a long comment? [yn]n
Finished recording patch 'patch-131016-02'

2.5 Build your project

準備が整ったところでビルドしてみよう。ソースのビルドの方法には2通りある。ひとつは Setup.hs スクリプトを利用する方法。もうひとつは cabal-install を利用する方法だ。ほとんどの場合 cabal-install を使う方法のほうが便利だ。

cabal-install を使ってビルドするには次のようにする。

$ cabal install --prefix=$HOME --user
Resolving dependencies...
Configuring haq-0.0...
Building haq-0.0...
以下省略

伝統的な方法でビルドするのは次のようにする。

$ runhaskell Setup configure --prefix=$HOME --user
$ runhaskell Setup build
$ runhaskell Setup install

これで haq プログラムが $HOME/bin に作成された。

2.6 Run it

実行例は次のようになる。

$ ~/bin/haq me
"Haq! me"

実行可能ファイルは ~/haq/dist/build/haq/にあるので、インストールのステップがなくても次のように実行することができる。

$ ~/haq/dist/build/haq/haq you
"Haq! you"

2.7 Build some haddock documentation

API の文書を dist/doc/* ディレクトリに作成する方法。まず、cabal-install を使う方法。

$ cabal haddock --executables
(中略)
Documentation created: dist/doc/html/haq/haq/index.html

管理人注: haq プロジェクトにはモジュールがないので --executable フラグが必要だった。どんなファイルが作成されたのかは次のようにしてコマンドラインから Safari を起動して確かめることができる。

$ open -a Safari dist/doc/html/haq/haq/index.html

伝統的な方法では、

$ runhaskell Setup haddock

文書が作成されない場合は、Haddock がインストールされているかどうか確かめる必要がある。Haddock は Cabal とは別のプログラムだ。また、ソースの中でスタイルを指定された文書は Haddock で作成した HTML 文書に反映される。

2.8 (Optional) Improve your code : HLint

管理人注:

HLint はソースのコーディング・スタイルを改善するための有用なツールだが、このプログでは省略する。

2.9 Add Some automated testing: QuickCheck

管理人注: この文書では QuickCheck 1.0 と 2.0 の両方について解説してあるが、このブログでは QuickCheck ver 2.0 以降についてのみ試してみる。システムに QuickCheck がないときは sudo cabal install quickcheck でインストールできる。モジュールは Test.QuickCheck だ。

Haq.hs コードの単純な性質をテストするのに QuickCheck を使ってみよう。最初に QuickCheck のテストモジュールを Tests.hs に作ってみよう。

import Data.Char
import Data.List
import Test.QuickCheck
import Text.Printf

main = mapM_ (\(s,a) -> printf "%-25s: " s >> a) tests

-- reversing twice a finite list, is the same as identity
prop_reversereverse s = (reverse . reverse) s == id s
  where _ = s :: [Int]

-- Dropping the "Haq! " stirng is the same as identity
prop_haq s = drop (length "Haq! ") (haqify s) == id s
  where haqify s = "Haq! " ++ s

tests = [("reverse.reverse/id", quickCheck prop_reversereverse)
        , ("drop.haq/id", quickCheck prop_haq)]

Test.hs プロジェクトをテストしてみたのが次の例だ。テストデータは QuickCheck が自動的に発生させる。

Tomokiyo-no-MacBook-Pro:haq tomokiyo$ runhaskell Test.hs
reverse.reverse/id : +++ OK, passed 100 tests.
drop.haq/id : +++ OK, passed 100 tests.

管理人注:

テストモジュールと言っても普通の Haskell のスクリプトだ。このテストモジュールでテストしているのは prop_haq s に含まれている haqify 関数だ。haqify 関数の property をテストするために prop_haq 関数が定義されている。この prop_haq 関数を quickCheck 関数の引数にするだけで haqify 関数のプロパティテストができる。

QuickCheck のチュートリアルは Real World Haskell のものが分かりやすい。

2.10 Running the test suite from darks

darcs を設定して編集結果をコミットするたびにテスト・スーツを動かすようにすることができる。そのためには --test フラグを用いる。

$ darcs setpref test "runhaskell Test.hs"
Changing value of test from '' to 'runhaskell Test.hs'

これで、フルセットの QuickCheck を動作させることができる。新しい編集の結果(Test.hs の追加)をコミットしてみよう。

$ darcs add Test.hs
$ darcs record --all --test
What is the patch name? patch-131020
Do you want to add a long comment? [yn]n
Running test...

reverse.reverse/id : +++ OK, passed 100 tests.
drop.haq/id : +++ OK, passed 100 tests.
Test ran successfully.

Running test...

reverse.reverse/id : +++ OK, passed 100 tests.
drop.haq/id : +++ OK, passed 100 tests.
Test ran successfully.

Finished recording patch 'patch-131020'

これで darcs によるリビジョン・コントロールの操作のたびに、--test フラグでパッチのテストをすることができる。

2.11 Tag the stable version, create a tar ball, and sell it!

Tag the stable version

プログラムの開発が進んで安定バージョンができたら、次のようにして darcs でタグを作る。

$ darcs tag
What is the patch name? 0.0
Do you want to add a long comment? [yn]n
Finished tagging patch 'TAG 0.0'

2.11.1 Create a tarball

安定板の tarball を作るのには Cabal も darcs もつかえるし、直接に tar コマンドを使ってもいい。

2.11.1.1 Using Cabal

cabalize したコードは次のように簡単に配布用の tarball を作ることができる。

$ cabal sdist
Building source dist for haq-0.0...
Preprocessing executable 'haq' for haq-0.0...
Source tarball created: dist/haq-0.0.tar.gz

cabal を使うと tarball の作成のほかに、その tarball が HackageDB の要件を満たしているかどうかもチェックしてくれる。たとえば、LICENSE ファイルが存在している必要がある。cabal はソースコードの他にそれをビルドするためのファイルもパッケージ化する。そのほかの Test.hs や README などのファイルも tarball に含めるためには、次のフィールドを .cabal ファイルに追加しておく必要がある。

extra-source-files: Test.hs README

2.11.1.2 Using darks

cabal を使って tarball を使う方法以外に、darcs を使う方法もある。

Tomokiyo-no-MacBook-Pro:haq tomokiyo$ darcs dist -d haq-0.0
Created dist as /Users/tomokiyo/haq/haq-0.0.tar.gz

2.11.2 Check that your source package is complete

全てがうまくいったのを確かめるだけでなく、テンポラリのディレクトリでソースをビルドしてみる必要もある。

$ cp haq/haq-0.0.tar.gz ~/temp
$ cd ~/temp
$ tar xzf haq-0.0.tar.gz
$ cd haq-0.0
$ cabal configure
$ cabal build
$ dist/build/haq/haq me
"Haq! me"

taball にライブラリがあるときは上のコマンドに加えて Haddock を作る。

$ cabal haddock

2.11.3 Upload your package to Hackage

上に述べてきたどの方法を使っても自分のパッケージを作ることができる。このパッケージはウェブのインターフェースを利用して Hackage パッケージとしてアップロードすることができる。ウエブ・インターフェースではアップロード前のチェックができるので、アップロード前にチェックしておいた方がいい。

2.12 Summary

最終的に haq ディレクトリには次のファイルが含まれているはずだ。

$ ls
Haq.hs  README  Test.hs  dist  haq.cabal
LICENSE  Setup.hs  _darcs  haq-0.0.tar.gz

前へ 目次 次へ
by tnomura9 | 2013-10-19 23:35 | Haskell | Comments(0)
<< Windows で Cabal... How to write a ... >>