7/19/2011

第6回 Common Lispライブラリを書く

 僕のブログで「Modern Common Lispはターゲットをどこに置いているのか」という質問をいただきました。最初は環境構築から始まっており、初心者向けに見えますが、次はHello, Worldもせずにライブラリの解説をしています。

 Modern Common Lispのターゲットは、これからのCommon Lispを学びたい人です。当初はこの連載を読めばCommon Lispについてのすべてを学べるAll-In-One形式にしようと考えていたのですが、それでは時間がかかりすぎてしまうため、いくつかの過程を省いて進めます。たとえば、Lispでは必要なリスト処理などはここでは解説しません。理由は、それを学ぶための書籍が既に多く存在するからです。Common Lispの基本文法はそれらの書籍を参照してください。この連載は、Common Lispの入門書と並行、または読了後に読むことをおすすめします。

 さて、前回の僕の記事では主要なライブラリとその使い方について紹介しました。今回は自分のCommon Lispのライブラリを書く手順についてです。

Sleep Sortのライブラリをつくろう

 1ヶ月以上前のことになりますが、Sleep Sortというソートアルゴリズムが話題になりました。

 実装が簡単なので、例として今回はこのライブラリを作りたいと思います。

CL-Projectでスケルトン生成

 まずはライブラリの雛形を作ります。雛形の生成にはCL-Projectというライブラリを使います。まずはQuicklispでインストールしましょう。

(ql:quickload :cl-project)

 雛形を作るには関数make-projectを使います。あらかじめ依存することが分かっているライブラリはこのタイミングで指定しておきましょう。今回はcl-annot(後述)と、スレッドを使いそうなのでbordeaux-threadsの2つを指定しています。

(cl-project:make-project #p"lib/sleepsort/"
  :author "Eitarow Fukamachi"
  :email "e.arrows@gmail.com"
  :license "LLGPL"
  :depends-on '(:bordeaux-threads cl-annot))
;-> writing /Users/fukamachi/Programs/lib/sleepsort/.gitignore
    writing /Users/fukamachi/Programs/lib/sleepsort/README.markdown
    writing /Users/fukamachi/Programs/lib/sleepsort/sleepsort-test.asd
    writing /Users/fukamachi/Programs/lib/sleepsort/sleepsort.asd
    writing /Users/fukamachi/Programs/lib/sleepsort/src/sleepsort.lisp
    writing /Users/fukamachi/Programs/lib/sleepsort/t/sleepsort.lisp
;=> #P"/Users/fukamachi/Programs/lib/sleepsort/sleepsort.asd"

 これで#p"lib/sleepsort/"にスケルトンができました。空のプロジェクトはそのままの状態でもql:quickloadすることができます。

(ql:quickload :sleepsort)
;-> To load "sleepsort":
      Load 1 ASDF system:
        sleepsort
    ; Loading "sleepsort"
    [package sleepsort]
;=> (:SLEEPSORT)

※注) もし#p"lib/sleepsort/"にパスが通っていない場合、REPLを再起動するとロードできなくなります。ローカルのプロジェクトをQuicklispでロードできるようにするには第2回 Quicklispによるライブラリ環境を参照してください。

雛形の構成

 CL-Projectが生成する雛形は以下のような最小構成です。

  • README.markdown: README。
  • sleepsort.asd: ライブラリ(system)の定義ファイル。
  • sleepsort-test.asd: ライブラリのテスト用の定義ファイル。
  • src/
    • sleepsort.lisp: メインのソースファイル。
  • t/
    • sleepsort.lisp: メインのテストファイル。

 ディレクトリトップには.asdファイルが2つあります。これは他の言語で言うところのMakefileです。ASDFによるライブラリの定義ファイルです。Quicklispはこのファイルから必要なファイルを判断してライブラリをロードしています。

 srcディレクトリは主なソースコードを置く場所です。この中には最初1つのファイルが置かれていますが、他にファイルを分けたいと思ったときにはこのディレクトリにファイルをどんどん追加していきます。

 tディレクトリは自動テストを置く場所です。

関数を実装

 では、肝心の関数の定義をします。src/sleepsort.lispを開いてください。以下のようになっているはずです。

#|
  This file is a part of sleepsort project.
  Copyright (c) 2011 Eitarow Fukamachi (e.arrows@gmail.com)
|#

(in-package :cl-user)
(defpackage sleepsort
  (:use :cl))
(in-package :sleepsort)

;; blah blah blah.

 これにsleepsortという関数を追加します。

#|
  This file is a part of sleepsort project.
  Copyright (c) 2011 Eitarow Fukamachi (e.arrows@gmail.com)
|#

(in-package :cl-user)
(defpackage sleepsort
  (:use :cl)
  (:import-from :bordeaux-threads
                :make-thread
                :join-thread))
(in-package :sleepsort)

(cl-annot:enable-annot-syntax)

@export
(defun sleepsort (&rest args)
  "A function to do 'sleep sort' arguments."
  (let* (result
         (threads (mapcar (lambda (arg)
                            (bordeaux-threads:make-thread
                             (lambda ()
                               (sleep arg)
                               (push arg result))))
                          args)))

    (dolist (thread threads)
      (bordeaux-threads:join-thread thread))

    (nreverse result)))

 @exportアノテーションを有効にするためにcl-annotを使っています。このアノテーションを使うと、指定した関数がパッケージ外でも参照できるようになります。

 cl-annotの詳しい解説は、作者の松山が今後紹介記事を書いてくれる予定です。

テストを書く

 モダンなライブラリに自動テストは欠かせません。雛形にはテスト用のファイルも含まれています。t/sleepsort.lispを開いてください。

#|
  This file is a part of sleepsort project.
  Copyright (c) 2011 Eitarow Fukamachi (e.arrows@gmail.com)
|#

(in-package :cl-user)
(defpackage sleepsort-test
  (:use :cl
        :sleepsort
        :cl-test-more))
(in-package :sleepsort-test)

(plan nil)

;; blah blah blah.

(finalize)

 この"blah blah blah."の部分を消して、以下のように置き換えてみます。

(diag "Testing 'sleepsort'. Wait some seconds...")
(is (sleepsort 5 3 6 3 6 3 1 4 7) '(1 3 3 3 4 5 6 6 7))

 テストを走らせるには(test-system :sleepsort)を実行します。

(test-system :sleepsort)
To load "sleepsort-test":
  Load 1 ASDF system:
    sleepsort-test
; Loading "sleepsort-test"
[package sleepsort-test]
# Testing 'sleepsort'. Wait some seconds...
ok 1

(:SLEEPSORT-TEST)

 Sleep Sortの実行は、その性質上時間がかかります。7秒ほど待ったあと、"ok"と表示されればテスト成功です。

 詳しいCL-TEST-MOREの説明はhttps://github.com/fukamachi/cl-test-moreを参照してください。

Quicklispに登録する

 せっかく作った有用なライブラリはQuicklispに登録すべきです。現在Quicklispへの登録は承認制になっており、月に一度の更新時に取り込まれます。日にちは固定ではないですが、だいたい毎月20日前後に更新されます。

 登録の申請はGitHub Issuesで行います。

 右上の「New Issue」をクリックし、ライブラリ名とリポジトリのURLを書いて登録してください。

おわりに

 さて、今回は自分のライブラリを作って公開するまでを紹介しました。公開するためでなくても、何かアプリケーションを作るときはasdファイルを書いてモジュール単位で管理するため、Common Lispでまとまったプログラムを書くときには必要な手順でしょう。

 次回の僕の回ではCL-TEST-MOREでの自動テストについてより詳しく解説します。

0 件のコメント:

コメントを投稿