実は Gauche をインストールしていました。

もう二ヶ月前になりますが、多値関連のエントリで shiro さんに指摘を受けたことから、やっぱり Scheme の環境をちゃんと持っておかなくてはと思い、自分の環境に Gauche を install し、遊んでみることにしてました。
その後、全く構築した環境にも Web にも接触できない状況に陥ってしまっていたのでそのまま放置になってしまっていますが……
取り敢えず、その時にやっておいたことを記録しておこうかと。

インストールした環境は、

coLinux (Debian/Sarge) on Windows XP
$ uname -a
Linux XXXXXXX 2.6.10-co-0.6.2 #5 Sat Feb 5 10:19:16 IST 2005 i686 GNU/Linux

です。
Debian/Sarge で aptitude を使って install できるのは 0.8.3-3 でしたが、2006/2/17 時点の gauche の最新版は 0.8.6 でした。

;; 今確認してみたら、
;;
;; 2006/4/12
;; Gauche 0.8.7: 大きなメンテナンスリリース
;;
;; なんてことになってる……

この Debian/Sarge では、基本的には aptitude で package を管理する方針としているので、取り敢えずは aptitude で install しておくことにしました。
;; 今のところ make install しているのは Trac と CUnit だけ。
問題ある様なら、その時には source から install し直すということで。

aptitude で、gauche を選択して install すると、

[インストール] gauche
[インストール] gauche-doc
[インストール] gauche-gdbm
[インストール] gauche-gl
[インストール] gauche-gtk
[依存関係によりインストール] freeglut3
[依存関係によりインストール] libglut3
[依存関係によりインストール] libgtkglext1
[依存関係によりインストール] slib
[維持] gpdf

が install されました。

$ whereis gosh
gosh: /usr/bin/gosh /usr/share/man/man1/gosh.1.gz
$ gosh -V
Gauche scheme interpreter, version 0.8.3 [utf-8,pthreads]

と gosh (0.8.3) が install されていることが確認できました。

但し、この時点で、

といった問題が。
多分、何れも XEmacs なせいかと。

gauche-refj.info の方は文字コードの問題かとも思ったのですが、GNU Info では読めるのでそうではない様です。
追ってみると、どうやら gauche-refj-info の Tag Table に書かれた offset がおかしい模様。(XEmacs の Info だと正しく解釈できないのかな?)
取り敢えず、各 node の offset を書き換えるコードを書いて実行。超適当ですが何とか読める様になりました。

run-scheme の方は、XEmacs の xscheme.el が、scheme インタプリタを起動する時のコマンドラインに、無条件に `-emacs' を付加する様にハードコードされていました。
xscheme.el に手を入れたくなかったので、scheme-program-name には wrapper となる sh script を登録し、その wrapper で `-emacs' を削ることにしました。
`-emacs' は、コマンドライン引数の先頭に指定される様になっていたので、その wrapper は、

#!/bin/sh
shift
gosh $*

としただけです。

これで動くには動いたんですが、

  • 基本的に xscheme-mode では、FSF Emacsscheme-mode と異なり、`gosh>' 等のプロンプトは表示しない様で、ちょっと判り辛いので、`-i' を渡す様に設定。
  • font-lock を有効に。
  • C-x C-e (advertised-xscheme-send-previous-expression) で評価時に、評価結果がポイントの直後に挿入されるのが気に入らないので、`?\n' を挿入する様にアドバイス
  • 上のせいで M-{n,p} (xscheme-yank-{pop,push}) 時に改行まで履歴として保持されてしまうので、履歴復元時には delete-char する様にアドバイス

ということで、

;; C-x C-e したら改行してから評価結果を表示。
(defadvice xscheme-send-string
  (before exp-newline activate)
  (insert ?\n))
;; xscheme-yank-{push,pop} では改行を削る。
(defadvice xscheme-yank-push (after shave-newline activate)
  (backward-delete-char))
(defadvice xscheme-yank-pop (after shave-newline-pop activate)
  (backward-delete-char))
;; xscheme-mode で font-lock.
(add-hook 'scheme-mode-hook #'(lambda () (font-lock-mode)))

として、取り敢えずは好みに使える様になりました。

しかし、やはり Gauche 専用のモードがあった方が良いでしょうね。

そこで、http://www.shiro.dreamhost.com/scheme/wiliki/wiliki.cgi?Gauche%3aEditingWithEmacs で幾つか紹介されている Majar Mode から、http://www.hh.iij4u.or.jp/~nishio/gauche-mode/ を使ってみることにしました。
この時点で最新の snap shot だった gauche-mode-20060110.tar.bz2 を download して、README の通りに make してみたんですが、

*** ERROR: string required, but got #f
Stack Trace:
_______________________________________
  0  (string->list format-string)
        At line 37 of "/usr/share/gauche/0.8.3/lib/srfi-29/format.scm"
  1  (format #f ";; exclude modules:\t~s\n" (cdr argv))
        At line 50 of "./make-sym.scm"
  2  (print-comments)
        At line 112 of "./make-sym.scm"
make: *** [BSD/gauche-module-symbol.dat] エラー 70

となってダメでした。
gauche で error を吐いてるので、XEmacs とは関係無さそうです。
README を見てみると、gauche-mode は最終更新が 2005-12-08 で、しかも `cleanup make-sym.scm' となっていて、error を起こした script そのものです。
これは gauche を最新に上げないと無理な気が。
一応、一世代古い gauche-mode も試してみましたが同じでした。

make -n してみると、いきなり gosh make-sym.scm とかして error になっているので、これを単独で実行してみても全く同じ結果に。
つまり、このスクリプトが gosh 上で正しく動作できていないということなので、gauche の構築した環境がマッチしてないという可能性が高いことになります。

となればやはり最新を試してみるべきなので、Gauche-0.8.6.tgz (2006/2/20時点の最新。現在は 0.8.7) を download して展開。
make && make test で問題無し。そのまま sudo make install として最新版のインストール完了。

$ gosh -V
Gauche scheme interpreter, version 0.8.6 [utf-8,pthreads]

となりました。

そして gauche-mode を make し直してみると、今度は成功しました。
しかし、私は普段、C-h を `backward-delete-char' に bind しているのですが、gauche-mode では `apropos' に bind してしまうので、bind し直すことにしました。

しかし、この gauche-mode、モードの実行時に gosh の process を生成して、その process にインタラクティブに評価させてるんですね。
これまで PerlRuby をその様な発想で利用したことはありませんでした。考えてみれば Perl/Ruby の debbugger や shell buffer (shell-mode) と同じなんですが、スクリプトの編集モードとそれを括りつける発想がありませんでしたねえ。
Emacs Lisp では当然の様にやってた訳ですが、Emacs Lisp だから特別に感じていた (そもそも EmacsEmacs Lispインタプリタな訳ですし) ということでしょうね。
Scheme ということで、Emacs Lisp と同様に利用したいという強い欲求から来たものでしょうか。素晴しいです。

それならばついでに、という事で、Emacs の scratch buffer と同様のものを作ってしまうことにしました。

;; Create scratch buffer for Gauche.
(defconst gauche-util-help-message
  ";; If you want to exit this buffer, type C-c C-q.")
(defun gauche-util-create-scratch-buffer ()
  "Create scratch buffer for Gauche."
  (interactive)
  (let ((sbuf (generate-new-buffer "*gauche scratch*")))
    (set-buffer sbuf)
    (insert
     (concat initial-scratch-message
             gauche-util-help-message
             "\n\n"))
    (save-excursion
      (goto-char (point-min))
      (let ((end (re-search-forward "lisp" nil nil nil))
            (start (match-beginning 0)))
        (replace-match "gauche" nil nil)))
    (set-buffer-modified-p nil)
    (switch-to-buffer sbuf)
    (gauche-mode)
    (save-excursion
      (goto-char (point-min))
      (let ((end (re-search-forward "for gauche evaluation" nil nil nil))
            (start (match-beginning 0)))
        (add-text-properties start end '(face font-lock-reference-face))))))
(defun gauche-util-kill-scratch-buffer ()
  "Kill scratch buffer for Gauche."
  (interactive)
  (progn
    (gauche-kill-gauche-process)
    (kill-buffer (current-buffer))))

(global-set-key [(control q) G] 'gauche-util-create-scratch-buffer)
(add-hook 'gauche-mode-hook
	  (lambda () (define-key (current-local-map)
                 [(control c) q] 'gauche-util-kill-scratch-buffer)))

このコード、scratch buffer の生成時に挿入されている文字列のうち、

for Lisp evaluation.

となっているところを、

for Gauche evaluation.

と書き変えて更に強調する処理を加えるため*だけ*に、余計なコードが歪な構成で入ってますが、それはご愛嬌ということで。あと、そもそも gauche-mode が XEmacs でしか動作しないので、このコードも XEmacs 以外のことは何も考えてません。
でも、そろそろ本当に FSF Emacs に移行しなきゃと思ってるんですけど、どんどん自分で自分の首を絞めてますね。

その他、gauche-mode の軽い設定など。

C-x C-e で評価すると、評価結果が minibuffer に表示されますが、末尾に改行が付いていて、不必要に minibuffer が拡がってしまうので、

;; C-x C-e 時に minibuffer が不必要に拡がるのを抑止。
(defadvice gauche-message (around expand-echoarea activate)
  "Not expand echo area, when the message was single-line."
  (let* ((fmt (ad-get-arg 0))
         (message (ad-get-args 1))
         (lines (with-temp-buffer
                  (insert (car message))
                  (count-lines-buffer))))
    (if (= 1 lines)
        (message fmt (car message))
      ad-do-it)))

としてそれを抑止してみました。
Emacs Lisp の M-: と同様の動作をして貰うために、

;; eval-expression.
(defun gauche-util-eval-expression (sexp)
  "Evaluate SEXP and print value in minibuffer."
  (interactive (list (read-string "Sexp: ")))
  (gauche-send-string-to-process (gauche-process) sexp))
(add-hook 'gauche-mode-hook
	  (lambda ()
		  (define-key (current-local-map)
        ;; [(control c) (meta :)] 'gauche-util-eval-expression)))
		    [(meta control :)] 'gauche-util-eval-expression)))

として M-C-: で minibuffer での評価もできる様にしてみました。

また、function-menu (fume) が動作してくれなくて悲しかったので、

;; setting for function-menu (fume).
(add-to-list 'fume-function-name-regexp-alist
    ;; Gauche
    '(gauche-mode . fume-function-name-regexp-scheme))
(add-to-list 'fume-find-function-name-method-alist
    ;; Gauche
    '(gauche-mode . fume-find-next-scheme-function))
(add-hook 'gauche-mode-hook
          (lambda ()
    (define-key (current-local-map) [(control c) r] 'fume-rescan-buffer)
    (define-key (current-local-map) [(meta p)] 'fume-goto-previous-function)
    (define-key (current-local-map) [(meta n)] 'fume-goto-next-function)))

と設定を追加しました。

こんな設定で、それなりに Emacs Lisp ライクな利用環境になってます。
あとは debugger かなあ。;; これは苦しいなあ。

しかし、gauche を使う設定とかで現実逃避してただけで、多値のこととか、

(use gauche.collection)
#<undef>
(fold2 (lambda (elt a b) (values (min elt a) (max elt b)))
       256 0
       (list 1 2 34 5 678 9 0 987 6 54 321))
0, 987

とかして、おおー、多値になるなるー、ってしただけです。
全く何やってんだか……。