#:g1: frontpage

 

cl-qprintの紹介

Posted 2014-10-22 15:00:00 GMT

(LISP Library 365参加エントリ)

 LISP Library 365 の296日目です。

cl-qprintとはなにか

 cl-qprintは、Robert Marlow氏とMax Rottenkolber氏によるRFC 2045のQuoted-Printableを扱うライブラリです。

パッケージ情報

パッケージ名cl-qprint
Quicklisp
CLiKiCLiki: cl-qprint
Quickdocscl-qprint | Quickdocs
CL Test Grid: ビルド状況cl-qprint | CL Test Grid

インストール方法

(ql:quickload :cl-qprint)

試してみる

 どんな関数があるかは、Quickdocsで確認できます。

 内容はシンプルにencodeとdecodeのみ。
入力にはオクテットかオクテットのストリームが使えます。

(qprint:encode (*:string-to-octets "Now's the time for all folk to come to the aid of their country."))
;=>  "Now's=20the=20time=20for=20all=20folk=20to=20come=20to=20the=20aid=20of=20th=^M
;    eir=20country."

(qprint:decode (qprint:encode (map 'vector #'char-code "Now's the time for all folk to come to the aid of their country."))) ;=> #(78 111 119 39 115 32 116 104 101 32 116 105 109 101 32 102 111 114 32 97 108 ; 108 32 102 111 108 107 32 116 111 32 99 111 109 101 32 116 111 32 116 104 101 ; 32 97 105 100 32 111 102 32 116 104 101 105 114 32 99 111 117 110 116 114 121 ; 46)

(with-open-stream (in (*:make-byte-array-input-stream (*:string-to-octets "Now's the time for all folk to come to the aid of their country."))) (qprint:encode in)) ;=> "Now's=20the=20time=20for=20all=20folk=20to=20come=20to=20the=20aid=20of=20th=^M ; eir=20country."

(with-open-stream (in (*:make-byte-array-input-stream (*:string-to-octets "おはよう日本おはよう日本おはよう日本"))) (qprint:encode in)) ;=> "=E3=81=8A=E3=81=AF=E3=82=88=E3=81=86=E6=97=A5=E6=9C=AC=E3=81=8A=E3=81=AF=E3=^M ; =82=88=E3=81=86=E6=97=A5=E6=9C=AC=E3=81=8A=E3=81=AF=E3=82=88=E3=81=86=E6=97=^M ; =A5=E6=9C=AC"

(*:octets-to-string (qprint:decode (qprint:encode (*:string-to-octets "おはよう日本おはよう日本おはよう日本")))) ;=> "おはよう日本おはよう日本おはよう日本"

まとめ

 今回は、cl-qprintを紹介してみました。
一発物は紹介が楽です。

cl-cronの紹介

Posted 2014-10-21 15:00:00 GMT

(LISP Library 365参加エントリ)

 LISP Library 365 の295日目です。

cl-cronとはなにか

 cl-cronは、Mackram Ghassan Raydan氏作のCommon Lispでのcron実装です。

パッケージ情報

パッケージ名cl-cron
Quicklisp
CLiKiCLiki: cl-cron
Quickdocscl-cron | Quickdocs
CL Test Grid: ビルド状況cl-cron | CL Test Grid

インストール方法

(ql:quickload :cl-cron)

試してみる

 どんな関数があるかは、Quickdocsで確認できます。

 Lisp処理系でcron的なものを実現したものは幾つかあるようなのですが、cl-cronは処理系内部からLispの関数を実行するタイプのようです。

(cron:start-cron)

(cron:stop-cron)

で実行開始/停止で、ジョブの投入には、make-cron-jobを利用します。

(cron:make-cron-job (lambda () (print "hello")))

とすれば、毎分helloを出力するジョブが投入されます。実行時刻の指定は大体cronと同じです。

start-cronは、起動時にcron:*cron-load-file*で指定したファイルを読みに行くので、このファイルにジョブを記載しておけばまとめてジョブを投入できます。

(setq cron:*cron-load-file* "~/.cl-cron")

として、~/.cl-cronに、

;;; 毎時の0、15、30、45で実行
(cron:make-cron-job (lambda () (print "hello"))
                    :minute '(0 15 30 45)) 

;;; 毎週月曜の0:00に実行 (cron:make-cron-job (lambda () (print "hello")) :minute 0 :hour 0 :day-of-week 0)

;;; 毎分実行 (cron:make-cron-job (lambda () (print "hello")))

;;; *EOF*

のようなものを定義して利用することが可能です。

まとめ

 今回は、cl-cronを紹介してみました。
Common Lisp製のデーモンかなにかの中で定期実行したい場合に便利そうですね。

glintの紹介

Posted 2014-10-20 15:00:00 GMT

(LISP Library 365参加エントリ)

 LISP Library 365 の294日目です。

glintとはなにか

 glintは、Naoki Koguro氏作のGauche用のコードチェッカーです。

パッケージ情報

パッケージ名glint
プロジェクトサイトglint

インストール方法

 プロジェクトサイトからダウンロードしてきて、configure/make/make installでglintコマンドが生成されます。

 Gauche 0.8.13用とのことで、最新のGaucheでは動作未確認かと思います。

試してみる

 glintがリリースされたのは、2008年のことで早6年前になりますが、当時開催のgauche.night #2での発表の動画がありますので、これを観るのが一番分かりやすいかなと思います。

 glintではGauche内部の中間表現を元にチェックしているのでGaucheの実際の動作に即した詳細な結果が得られます。

 一応、以前のsclintの例+αで比べてみると、

(define (foo x)
  (if (= x 0)
	1
           (foo (- x 1))))

(if 1 2 3 4)

(define)

(let () a)

(if (= car x 0) a b)

(define morlis (lambda (x) x))

(define (morlis y) y)

;; (use srfi-42) (list-ec (: e '(1 2 3 4)) e)

のようなものだと、

$ glint /tmp/foo.scm
/tmp/foo.scm:6: error: syntax-error: malformed if: (if 1 2 3 4)
/tmp/foo.scm:8: error: syntax-error: (define)
/tmp/foo.scm:10: error: a(user) referenced but not defined
/tmp/foo.scm:12: error: a(user) referenced but not defined
/tmp/foo.scm:12: error: b(user) referenced but not defined
/tmp/foo.scm:12: error: x(user) referenced but not defined
/tmp/foo.scm:20: error: #<generic object-apply (8)> can't be applied with arguments (: #<unidentified> (1 2 3 4))
/tmp/foo.scm:20: error: e(user) referenced but not defined
/tmp/foo.scm:20: error: list-ec(user) referenced but not defined

のような感じになります。
(use srfi-42)を有効にすれば、

/tmp/foo.scm:6: error: syntax-error: malformed if: (if 1 2 3 4)
/tmp/foo.scm:8: error: syntax-error: (define)
/tmp/foo.scm:10: error: a(user) referenced but not defined
/tmp/foo.scm:12: error: a(user) referenced but not defined
/tmp/foo.scm:12: error: b(user) referenced but not defined
/tmp/foo.scm:12: error: x(user) referenced but not defined

のようにエラーも減少します。

まとめ

 今回は、glintを紹介してみました。
動画のデモにもありますが、Emacsのflymakeからも使えるようになっていて便利そうです。

Lucid CL: Adviceの紹介

Posted 2014-10-19 15:00:00 GMT

(LISP Library 365参加エントリ)

 LISP Library 365 の293日目です。

Lucid CL: Adviceとはなにか

 Lucid CL: Adviceは、Lucid CLのアドバイス機構です。

パッケージ情報

パッケージ名Lucid CL: Advice
ドキュメントLiquid CL: 6.3 The Advice Facility

インストール方法

 Lucid CL/Liquid CLでは標準で使えます。LCLパッケージで定義されていますが、CL-USERからも使えるようになっています。

試してみる

 今回もこれまでのアドバイス機構の紹介と同じ例ですが、Lucid CL版で他と違っているのは、基本的にaroundのみで、それを他のアドバイスの内側に追加するか、外側に追加するかを指定するという所です。
動作的には、aroundしかないのでbeforeに相当するものは、最後にadvice-continueし、afterは、最初にadvice-continueしてから後の処理を追加する、という感じになります。
動作的にと書いたのは、ややこしいことに、:insideの別名として:after、:outsideの別名として:beforeが使えるからなのですが、:before/:afterで考えると混乱するので、ここでは、:inside/:outsideのみで紹介します。
ちなみに、指定しなければデフォルトで:outsideを指定したことになります。
尚、Lucid CLのアドバイスも定義する順番で動作が変わるので定義順が重要になっています。

(defun matu (x)
  (format t "~&>>~A<<~%" x))

(matu 8) ;>> >>8<< ;=> NIL


(defadvice (matu around0) (n)
  (prog2
    (write-line "around0 ==>")
    (advice-continue n)
    (write-line "around0 <==")))

(defadvice (matu around1 (:outside around0)) (n) (prog2 (write-line "around1 ==>") (advice-continue n) (write-line "around1 <==")))

(defadvice (matu before0 (:inside around0)) (n) (write-line "before0:") (advice-continue n))

(defadvice (matu before1 (:outside before0)) (n) (write-line "before1:") (advice-continue n))

(defadvice (matu after0 (:inside around0)) (n) (prog1 (advice-continue n) (write-line "after0:")))

(defadvice (matu after1 (:outside after0)) (n) (prog1 (advice-continue n) (write-line "after1:")))

(matu 8) ;>> around1 ==> ;>> around0 ==> ;>> before1: ;>> before0: ;>> >>8<< ;>> after0: ;>> after1: ;>> around0 <== ;>> around1 <== ;=> NIL

 また、マクロにもアドバイスは定義可能です。

(defmacro mydefun (name (&rest args) &body body)
  `(defun ,name (,@args) ,@body))

(defadvice (mydefun inline) (form env) (destructuring-bind (def name args &body body) form (declare (ignore def args body)) `(progn (declaim (inline ,name)) ,(advice-continue form env))))

(mydefun foo (n) n) ;===> (PROGN (DECLAIM (INLINE FOO)) (DEFUN FOO (N) N))

 他、アドバイスの削除には、remove-adviceが使え、アドバイスのdescribeには、describe-adviceが定義されています。

(describe-advice 'matu)
;>> Advice AROUND1: #<Interpreted-Function (:ADVICE MATU AROUND1) C0E767>
;>>   Advice AROUND0: #<Interpreted-Function (:ADVICE MATU AROUND0) C0E717>
;>>     Advice AFTER1: #<Interpreted-Function (:ADVICE MATU AFTER1) C0E6C7>
;>>       Advice AFTER0: #<Interpreted-Function (:ADVICE MATU AFTER0) C0E677>
;>>         Advice BEFORE1: #<Interpreted-Function (:ADVICE MATU BEFORE1) C0E627>
;>>           Advice BEFORE0: #<Interpreted-Function (:ADVICE MATU BEFORE0) C0E4B7>
;>>             Original definition: #<Interpreted-Function (NAMED-LAMBDA MATU (X) (BLOCK MATU (FORMAT T "~&>>~A<<~%" X))) BF7AB7>
;=> NIL

まとめ

 今回は、Lucid CL: Adviceを紹介してみました。
MIT Lispマシン系統とはちょっと違った方式でなかなか面白いです。

Clozure CL: Watched Objectsの紹介

Posted 2014-10-19 09:00:00 GMT

(LISP Library 365参加エントリ)

 LISP Library 365 の292日目です。

Clozure CL: Watched Objectsとはなにか

 Clozure CL: Watched Objectsは、Clozure CLの標準機能でオブジェクトへの書き込みを監視する機能です。

パッケージ情報

ドキュメントClozure Documentation: 4.12. Watched Objects

インストール方法

 Clozure CLの拡張なので標準で利用可能です。パッケージはCCLパッケージですが、CL-USERでも使えるようになっています。

試してみる

 基本的にどんなLispオブジェクトでも変更を検出できます(クラスのインスタンス等も可)

(defvar *v* (vector 0 1 2 3 4 5))

*v* ;=> #(0 1 2 3 4 5)

(watch *v*) ;=> #(0 1 2 3 4 5)

(incf (svref *v* 3) 10) ;!> Write to watched uvector #(0 1 2 3 4 5) at index 3

 少しわかりにくい監視対象のオブジェクトとしてハッシュテーブルとリストがあります。
ハッシュテーブルは、バックエンドのベクタの書き込みを禁止する方法で実現しているのでエラーが直感的でないことと、リストの場合は、1つのセルを監視対象とする点です。

(defvar *h* (*:plist-hash-table '(:a 0 :b 1 :c 2 :d 3 :e 4 :f 5)))

(watch *h*)

(incf (gethash :a *h*)) ;!> Write to watched uvector #<HASH-TABLE-VECTOR #x7FFFF7FC300D> at index 149

(defvar *L* (list 'car 'cadr 'caddr))

*L* ;=> (CAR CADR CADDR)

(watch *L*)

(setf (car *L*) 0) ;!> Write to the CAR of watched cons cell (CAR CADR CADDR)

(setf (cdr *L*) 0) ;!> Write to the CDR of watched cons cell (CAR CADR CADDR)

(setf (cadr *L*) 1) ;=> 1

*L* ;=> (CAR 1 CADDR)

また、解除には、unwatchを使います。

(unwatch *L*)

まとめ

 今回は、Clozure CL: Watched Objectsを紹介してみました。
Successfull Lispの30章でもwatchのことが取り上げられていました(Successful Lisp - Chapter 30)が、watchがあるのはどうもMCL系統だけみたいですね。
デバッグの時には活躍することもありそうです。

defmethodの&rest引数でダブルディスパッチにaroundメソッドの組み合わせ

Posted 2014-10-18 14:00:00 GMT

defmethodの&rest引数でもディスパッチしたい

 結論からいうと標準のCommon Lispでは無理です(MOPでカスタマイズした総称関数でも使わない限り)が、多重メソッドでないSmalltalkのようなオブジェクト指向システムの、ダブルディスパッチという技が使えます。

(defmethod foo ((x integer) &rest args)
  (cons (list 'integer x)
        (when args
          (apply #'foo args))))

(defmethod foo ((x list) &rest args) (cons (list 'list x) (when args (apply #'foo args))))

(defmethod foo (x &rest args) (cons (list 't x) (when args (apply #'foo args))))

(foo 1 2 3 '() 5 #(1 2 3 4) 1) ;=> ((INTEGER 1) (INTEGER 2) (INTEGER 3) (LIST NIL) (INTEGER 5) (T #(1 2 3 4)))

aroundメソッドを組み合わせてみる

 毎度のwhen argsが面倒臭いと思ったのですが、aroundで検査してやれば良いんじゃないかと思って試してみました。

(defmethod foo :around (x &rest args)
  (when args
    (call-next-method)))

(defmethod foo ((x integer) &rest args) (cons (list 'integer x) (apply #'foo args)))

(defmethod foo ((x list) &rest args) (cons (list 'list x) (apply #'foo args)))

(defmethod foo (x &rest args) (cons (list 't x) (apply #'foo args)))

(foo 1 2 3 '() 5 #(1 2 3 4) 1) ;=> ((INTEGER 1) (INTEGER 2) (INTEGER 3) (LIST NIL) (INTEGER 5) (T #(1 2 3 4)))

割合に良さそうです。

まとめ

 特にこれといったオチもなく

srfi 96の紹介

Posted 2014-10-18 10:30:00 GMT

(LISP Library 365参加エントリ)

 LISP Library 365 の291日目です。

srfi 96とはなにか

 srfi 96は、Aubrey Jaffer氏によるSLIBを読み込むために必須なものを規定したSRFIです。

パッケージ情報

パッケージ名srfi 96
SRFI 96SRFI 96: SLIB Prerequisites

試してみる

 そもそもSLIBとはなにかというと、Aubrey Jaffer氏により1992年から開発が開始されたライブラリで、Common Lisp風の機能をScheme処理系に提供するところからスタートしたようです。
さて、明示的にライブラリを読み込むという手順でsrfi 96をサポートしているのは、Larceny位のようですが、Larcenyでは、

(require 'srfi-96)

で利用できますが、SLIBが必要になります。
また、(require 'srfi-96)をするのは、slibをrequireするのと同義のようです。
それで行くとGaucheの(use slib)もsrfi 96みたいなものなのでしょうか。

(scheme-implementation-type)
;=> larceny

(scheme-implementation-version) ;=> "0.97"

(scheme-implementation-type) ;=> |STklos|

(scheme-implementation-version) ;=> "1.10"

t ;=> #t

nil ;=> #f ;; STklos (scheme-implementation-type) ;=> |STklos|

(scheme-implementation-version) ;=> "1.10"

というようにCommon Lispで同じみな感じのものが使えるようになります。

まとめ

 今回は、srfi 96を紹介してみました。
STklosが縦棒のエスケープを使うことで思い出したのですが、STklosは、デフォルトでリーダーが小文字に変換するようで、小文字にされないようにするには、縦棒を使うようです。
Common Lispとは変換が逆の動作なのですが、Gaucheでも、オプションに-fcase-fold付きで起動するとこの動作になるようで(Gaucheの最近のバージョンではコマンドラインオプションが効かない?)、この辺りはSTklos由来の動作なのでしょうか。

scribbleの紹介

Posted 2014-10-17 10:00:00 GMT

(LISP Library 365参加エントリ)

 LISP Library 365 の290日目です。

scribbleとはなにか

 scribbleは、Fare Rideau氏作のCommon LispでScribble記法を利用できるようにするライブラリです。

パッケージ情報

パッケージ名scribble
Quicklisp
CLiKiCLiki: Scribble
Quickdocsscribble | Quickdocs
CL Test Grid: ビルド状況scribble | CL Test Grid

インストール方法

(ql:quickload :scribble)

試してみる

 どんな関数があるかは、Quickdocsで確認できます。

 Racket(PLT Scheme)方面では、Eli Barzilay氏考案のScribbleという記法が良く使われるようです。
Scheme処理系に付属のマニュアル等でたまに使われているのを見掛けることもありますね。

@{文章はどういう風に書くんでしょうか}

@code{(defun hello (x) (princ "Hello, ") (princ x) (terpri))}

@code{(hello "foo bar baz")}

@example{(+ 1 2) -> @(+ 1 2)⏎}

@foo|--{bar}@|{baz}--|

こんな感じに書いたものが、

(let ((p "/tmp/foo.txt")
      (eof '#:eof)
      (*readtable* (copy-readtable nil)))
  (scribble:enable-scribble-at-syntax)
  (with-open-file (s p :direction :input :if-does-not-exist :error)
    (loop for i = (read s nil eof nil)
          until (eq i eof)
          collect i)))
;=>  (("文章はどういう風に書くんでしょうか")
;     (CODE "(defun hello (x)" "
;    "
;      "(princ \"Hello, \")" "
;    "
;      "(princ x)" "
;    "
;      "(terpri))")
;     (CODE "(hello \"foo bar baz\")") (EXAMPLE "(+ 1 2) -> " (+ 1 2) "⏎")
;     (FOO "bar}@|{baz"))

こんな感じに読まれます。

まとめ

 今回は、scribbleを紹介してみました。
コード例を沢山記述しつつホスト言語の機能を活用したい場合などには便利そうな記法ですね。

cl-jpl-utilの紹介

Posted 2014-10-16 11:00:00 GMT

(LISP Library 365参加エントリ)

 LISP Library 365 の289日目です。

cl-jpl-utilとはなにか

 cl-jpl-utilは、J.P. Larocque氏作のCommon Lispのユーティリティ集です。

パッケージ情報

パッケージ名cl-jpl-util
Quicklisp
CLiKiCLiki: cl-jpl-util
Quickdocscl-jpl-util | Quickdocs
CL Test Grid: ビルド状況cl-jpl-util | CL Test Grid

インストール方法

(ql:quickload :jpl-util)

試してみる

 どんな関数があるかは、Quickdocsで確認できます。

 JPLとあるのでNasaのJPLかなにかと思いましたが、J.P. Larocque氏のイニシャルということみたいです。
内容は良くあるユーティリティ集ですが、こざっぱりとした感じに纏まっています。

関数

  • 1or
  • a/an-number
  • accumulate-to-dynamic-vector
  • accumulate-to-hash-table
  • accumulate-to-list
  • accumulate-to-vector
  • adjacent-pairs
  • alist->hash-table
  • alist->plist
  • all
  • any
  • assoc*
  • best
  • check-bounding-indices
  • check-type*
  • circular-list
  • clear-traces!
  • coerce-boolean
  • combine-elements
  • compose
  • compose-1v
  • composite-lesser?
  • cond-replace
  • copy-object
  • csubtypecase
  • curry-left
  • curry-right
  • decode-time-duration
  • defclass*
  • defvar-unbound
  • delete-nth!
  • designated-class
  • designated-function
  • doseq
  • duplicates-p
  • empty?
  • english-list-format-control
  • ensure-type
  • eof-p
  • equivalent-hash-table-test
  • esubtypecase
  • find-duplicates
  • format-ordinal
  • format-time-duration
  • fractional
  • get-reasonable-real-time
  • get-reasonable-run-time
  • group-by-n
  • hash-table->alist
  • insert-at
  • integer->twos-complement
  • integer-digit-count
  • integer-digits
  • iterate-alist
  • iterate-plist
  • lambda*
  • lesser?
  • list-extract!
  • list-traces
  • map-adjacent-pairs
  • map-lines
  • mean
  • merge-alists
  • nsort
  • nstable-sort
  • nth-arg
  • option-clause-bind
  • package<
  • parse-progn
  • parse-sequence-type
  • parse-vector-type
  • partition-list
  • partition-set
  • plist->alist
  • proper-list?
  • push-append
  • push-nconc
  • read-lines
  • read-new-value
  • remove-duplicate-properties
  • remove-ordered-duplicates
  • set-equal
  • shuffle
  • shuffle!
  • sort
  • split-list!
  • square
  • stable-sort
  • standard-deviation
  • string-begin-equal
  • string-begin=
  • string-end-equal
  • string-end=
  • subseq*
  • subseq-displace
  • subtype-error-expected-supertype
  • subtype-error-type
  • subtypecase
  • symbol<
  • test-order-pred
  • twos-complement->integer
  • unique-pairs
  • vector-delete
  • vector-delete-range
  • verbosely
  • with-accessors*
  • with-extent-hooks
  • with-extent-hooks%
  • with-gensyms
  • with-list-iterator
  • with-range-iterator
  • with-safe-alloc
  • with-sequence-iterator
  • with-trace
  • with-vector-iterator
  • with-verbosity
  • xor
  • zip
  • zip*

変数

  • *verbose*

  • array-dimension
  • array-index
  • class-designator
  • extended-function-designator
  • format-control
  • function-designator
  • function-name
  • pathname-designator
  • subsecond-universal-time
  • subtype-error
  • universal-time

 面白そうなものを数点取り上げると、
formatの指示子が憶えられないので作られたような、english-list-format-control

(jpl-util:english-list-format-control)
;=>  "~#[~;~A~;~A and ~A~:;~@{~#[~;and ~]~A~^, ~}~]"

(format t (jpl-util:english-list-format-control "~A" "or") 1 2 3 4) ;>> 1, 2, 3, or 4 ;=> NIL

(format t (jpl-util:english-list-format-control) 1) ;>> 1 ;=> NIL

(format t (jpl-util:english-list-format-control) 1 2) ;>> 1 and 2 ;=> NIL

(format t (jpl-util:english-list-format-control)) ;=> NIL

(format t (jpl-util:english-list-format-control "~A" "そして") 1 2 3 4) ;>> 1, 2, 3, そして 4 ;=> NIL

良く使いそうな型の定義

(typep '(setf foo) 'jpl-util:function-name)
;=>  T

(typep -1 'jpl-util:universal-time) ;=> NIL

他ありがちな状況のためのもの

(jpl-util:coerce-boolean (member 'foo '(foo bar baz)))
;=>  T

位でしょうか。

まとめ

 今回は、cl-jpl-utilを紹介してみました。
cl-jpl-utilまさに日常的にCommon Lispを書いていて必要になったのをまとめたという感じのユーティリティですね。

SCLINTの紹介

Posted 2014-10-15 11:11:00 GMT

(LISP Library 365参加エントリ)

 LISP Library 365 の288日目です。

SCLINTとはなにか

 SCLINTは、Pertti Kellomäki氏作のScheme(R4RS)版のLintです。

パッケージ情報

パッケージ名SCLINT
CMU AI レポジトリPackage: lang/scheme/code/debug/sclint/

インストール方法

 ダウンロードしてきて展開するだけで使えますが、実行スクリプトではscmで実行するようになっています。

試してみる

 こんな感じの、foo.scmというファイルがあったとして、

(define (foo x)
  (if (= x 0)
	1
           (foo (- x 1))))

(if 1 2 3 4)

(define)

(let () a)

(if (= car x 0) a b)

(define morlis (lambda (x) x))

(define (morlis y) y)

$ sclint foo.scm

でチェックすると

sclint v. 0.9, Pertti Kellomaki 1992
Reading source files: /home/mc/sclint/foo.scm, done.
Checking indentation...done.
Checking special forms and argument counts...done.
foo.scm:3:Indentation does not match the logical structure.
foo.scm:4:Indentation does not match the logical structure.
foo.scm:7:Wrong number of subexpressions in if.
foo.scm:10:Missing variable and expression in a define form.
foo.scm:13:No bindings in a binding list. You should probably use begin instead.
foo.scm:16:Variable not defined in lexical context: x
foo.scm:17:Variable not defined in lexical context: a
foo.scm:18:Variable not defined in lexical context: b
foo.scm:21:Duplicate definition of morlis
foo.scm:24:Duplicate definition of morlis

のような感じでチェックしてくれます。
チェックしてくれるポイントですが、

  • インデントのずれ
  • 引数の数のチェック
  • 特殊形式の使い方
  • 重複した定義
  • 定義されていない変数

あたりのようです。
コードを眺めると移植性が高そうだったのでSagittariusで実行してみましたが、そのまま実行できるようです。
こんな感じにシェルスクリプトにできます。

#!/usr/bin/env sash

(import (rnrs))

(define SCLINTHOME ".../sclint/")

(for-each (lambda (f) (load (string-append SCLINTHOME f))) '("pexpr.scm" "read.scm" "environ.scm" "special.scm" "procs.scm" "top-level.scm" "checkarg.scm" "sclint.scm" "match.scm" "indent.scm"))

(sclint (cdr (command-line)))

まとめ

 今回は、SCLINTを紹介してみました。
1992年のものということで大分古いものですが、割合に今でも使えそうです。
主に教育目的での利用を想定しているとのことですが、入門あたりなら全然使えそうではあります。

Older entries (1811 remaining)