ラベル Common Lisp の投稿を表示しています。 すべての投稿を表示
ラベル Common Lisp の投稿を表示しています。 すべての投稿を表示

2010年1月30日土曜日

Scheme コードバトンに参加

次回3月予定のShibuya.lispに向けて、現在面白げな企画が進行中です。

Shibuya.lisp に向けて Scheme コードバトンするのはどうか?
第1回 Scheme コードバトンのお知らせ - ひげぽん OSとか作っちゃうかMona-

;; ■ これは何か?
;; Scheme のコードをバトンのように回していき面白い物ができあがるのを楽しむ遊びです。
;; 次回 Shibuya.lisp で成果を発表します。
;; Scheme 初心者のコードを書くきっかけに、中級者には他人のコードを読む機会になればと思います。
;;
;; ■ 2 つのルール
;;
;; (1)自分がこれだと思える変更をコードに加えて2日以内に次の人にまわしてください。
;; 「人に優しい」変更なら何でも良い。1文字の変更でも可。
;; 「人に優しい」とは例えば、次の人が読みやすいコードを書くなど。
;; コードを削るのもあり。
;;
;; (2)次の人にまわしコードが変更されるのを"見守る"。
;; この説明書きを含めてバトンが伝わった事を必ず確認してください。
;; 止まっていたら助けてあげてください。

自分もg00001さんのバトンから派生したCL版を弄らせてもらいました。ライブラリまわりの導入に手間取ったのがちょっと痛かったかも…とりあえずテスタくらいの役割は果たせたんじゃないかと思います。

それと、newlispも一応lisp風スクリプト言語ということで大元となるhigeponさんのバトンからforkしてnewlisp版も作ってみることに。
こちらはCLやSchemeと違って正しいコーディングスタイルが分かってないので、つらつらと手の赴くままに。

動作例は以下

[~/code/newlisp]$ newlisp scheme_button.lsp http://gist.github.com/273424.txt # 辞書ファイルをURLから取得
allowance: 割当量 [y/n/q]? y
defect: 欠点 [y/n/q]? n
errand: 使いっ走り [y/n/q]? y
exploration: 探査、探検 [y/n/q]? y
heap: 積み重ねた物 [y/n/q]? y
;; saving dict...done
[~/code/newlisp]$ cat words.txt
(allowance "割当量" 1 0)
(defect "欠点" 0 1)
(errand "使いっ走り" 1 0)
(exploration "探査、探検" 1 0)
(heap "積み重ねた物" 1 0)

scheme版と同様にコマンドラインからの利用で、 newlispバイナリ一つあれば動作するようになっているとは思います。

CL版弄った時間もあわせると2日以上かかっていますがまあ気にしない。

2009年9月12日土曜日

Swank server for newLISP

ひっそりと更新。

以前挑戦した「newLISPをSLIMEから動かす」が、一応お遊び程度に完成したので公開してみます。

http://github.com/kosh04/newlisp-files/tree/master >> swank-newlisp.lsp

簡単なREPLが使えるくらいで、SLIMEの特徴であるシンボル名の補完、定義ファイルへのジャンプなどなど実装されていない残念な出来です。

2009年7月15日水曜日

今朝の無題

Lispは未来に生きている - リリカル☆Lisp開発日記 - http://blog.bugyo.tk/lyrical/2009/02/lisp-15.html

そろそろCLのuniversal-timeがキリ番になりますね。

---

そういえば自分のGitHubのリポジトリをちまちま更新しました。 主に個人用に作っているのでフォローしている人がいるとなんだか申し訳ない気分です。

今のところの更新頻度は emacs-lisp > newlisp-files >> xyzzy-lisp こんな感じです(左に行くほど頻度が高い)。 研究室の端末がDebianなのでEmacsを弄りがちで、xyzzyとの挙動の違いを自作のxyzzy.elで埋めるのが主な目的。

---

それにしてもnewLISPは話題に乗りませんねー。 毎回検索の上位にこのブログが入っているのを見ると嬉しいような悲しいような…

変な愛着が湧いて今でも手探りで調べているnewLISP、もうちょっと他の人が言及してくれてもいいのに。と思うならまず自分からですかね。

2009年4月19日日曜日

GitHubアカウントをとりました

いくつかファイルを置いておいたので、よかったらどうぞ。

GitHubアカウント - github.com/kosh04

  • xyzzy/
    • etc/
      • newLISP - newlisp-mode用キーワードファイル
    • site-lisp/
      • cl.l - xyzzyにないCL関数の移植のようなもの
      • corman_search.l - CLのsearch関数移植
      • cygwin.l - 主にmanコマンドを利用するため
      • newlisp.l - newLISP編集用メジャーモード
      • redef.l - xyzzy組み込み関数を再定義したもの
      • util.l - 自作関数など
  • emacs-lisp/
    • xyzzy.el - xyzzy/CommonLisp/SLIMEの便利そうな関数を色々移植したもの
  • newlisp-files/
    • init.lsp - CLっぽい関数とか
    • newlisp.el - newLISP編集用メジャーモード

真面目にファイルの配布するならライセンスやマニュアルも考えるべきなんだろ うけど、今日はとりあえずここまで。gitに慣れるのに手間取って疲れた…

[追記]

GitHubのwebページがUTF-8らしいので、それに伴いファイルの文字コードも一部 UTF-8になっています。で、xyzzyだとファイルのコンパイル・ロード用の関数が デフォルトではShift_JISしか対応しないようなので、compile-file/loadの代わ りにmc-compile-file/mc-load-file関数などを使って明示的に文字コードを指定 してくだしあ。

後でREADMEくらいは作ろう。

[追記 (2009-12-08)]

ブラウザの文字化けよりもライブラリを実際に使う時の利便を考慮して、元のsjisに戻しました。

2009年4月3日金曜日

[LISP]マクロのエイリアス

マクロ名の定義にも setf が使えるらしいことに気づいたのでメモ。 ついでに xyzzy だと macro-function に setf 出来ないので定義しておく。 たぶん間違ってるけど。 # xyzzy, CLISP-2.44 で確認
#+xyzzy (defsetf macro-function si:*fset)

(progn
  (setf (macro-function 'if-progn)
        (macro-function 'when))
  (list (if-progn t "てー")
        (if-progn nil "てー")))
;=> ("てー" NIL)

(progn
  (setf (macro-function '&&)
        (macro-function 'and))
  (list (&& t "てー")
        (&& nil "てー")))
;=> ("てー" NIL)

(progn
  (setf (macro-function 'mvbind)
        (macro-function 'multiple-value-bind))
  (mvbind (a b c)
      (values 1 2 3)
    (list a b c)))
;=> (1 2 3)
; #+xyzzy だと (macro-function 'multiple-value-bind) => nil となりエラー

(progn
  (setf (macro-function 'defconst)
        (macro-function 'defconstant))
  (defconst e (exp 1))
  (list e (multiple-value-list
           (ignore-errors (let ((e pi)) e)))))
;=> (2.7182817 (NIL #<SYSTEM::SIMPLE-SOURCE-PROGRAM-ERROR #x19EE7919>))

(progn
  (setf (macro-function '++)
        (macro-function 'incf))
  (let ((n 1))
    (list n (++ n) (++ n))))
;=> (1 2 3)

(progn
  (setf (macro-function 'fn)
        (macro-function 'lambda))
  (remove-if (fn (x) (zerop (mod x 3)))
             '(0 1 2 3 4 5 6 7 8 9)))
;-> *** - FUNCTION: (FN (X) (ZEROP (MOD X 3))) is not a function name; try using a symbol instead
; #+GCL ではエラーにならずに (1 2 4 5 7 8) を返す。…なんでだ?

2009年2月17日火曜日

progvの途中

(let ((buffer-read-only nil))
  (declare (special buffer-read-only))
  (hogehoge))

Emacsのような動的束縛を使うなら上のように書くのがたぶん一般的なんだろうけど、動的束縛といえばprogvなんてものがあることに気づいたので以前自分で書いたものを引っ張ってきてみた。

(defmacro progv (symbols values &body body)
  (let ((label (gensym "progv-form"))
        (var (eval symbols))
        (val (eval values)))
    `(labels ((,label () ,@body))
       ((lambda (,@var)
          (declare (special ,@var))
          (funcall (function ,label)))
        ,@val))))

body部を変数束縛の外で実行する点では間違っていないと思う(たぶん)。 で、実行してみたところトップレベルではうまく動いているよう。

(defun hoge ()
  (let ((*x* 3))
    (progv '(*x*) '(4)
           (list *x* (symbol-value '*x*)))))
(hoge)
;=> (3 4)

ただしprogvを含む関数をコンパイルすると駄目になった。中を覗いてみると、

(si:closure-body (compile 'hoge))
=>
;; *制御文字の置き換えあり*
(lambda ()
  (system:*byte-code "^B^A^@廚^]^T^A^@^[^@Q^\^A
^A^\^A廛^U^B"
                     #(*x*
                       (lambda ()
                         (system:*byte-code "^@^B^@^E^@^A^@・・"
                                            #(*x*)))
                       (lambda #1=(*x*)
                         (declare (special . #1#))
                         (funcall #'#:progv-form350)))))

labelsの展開がうまくいってないらしく、内部関数名"#:progv-form350"が残っている。 ここまで辿ったけどコンパイルの動作がサッパリなのでここでお手上げ。

labels使わないでprogv実装しろってことかなあ。

2009年1月28日水曜日

[CL] 0から1000までに含まれる0をカウントする

http://d.hatena.ne.jp/rubikitch/20081120 より

(count #\0 (format nil "~{~D~}" (loop :for i :from 0 :to 1000 :collect i)))
;=> 193

Commom Lisp は文字列を弄ることが出来るから面白い。

2008年12月26日金曜日

'fooと#'fooの違いは環境の違い

QUOTEとFUNCTIONを使い分ける:もう少し詳しい説明 -- 逆引きCommonLisp

をぼんやり見ていて、そういえば FUNCTION と COERCE では環境が違うってうちの CLISP が言ってたのを思い出した。

(funcall '(lambda (x) (1+ x)) 1)
;; => Error
;; *** - FUNCALL: argument (LAMBDA (X) (1+ X)) is not a function.
;;       To get a function in the current environment, write (FUNCTION ...).
;;       To get a function in the global environment, write (COERCE '... 'FUNCTION).

CLHS にもそれらしい記述があったのでメモ。

CLHS: Function COERCE
If the result-type is function, and object is any function name that is fbound but that is globally defined neither as a macro name nor as a special operator, then the result is the functional value of object. If the result-type is function, and object is a lambda expression, then the result is a closure of object in the null lexical environment.

= objectがマクロ、スペシャル・オペレータ以外でグローバルに定義されたfboundな関数名を持っているなら、そのobjectの関数値を返す。 objectがラムダ式なら、空レキシカル環境なobjectのクロージャを返す。

CLHS: Special Operator FUNCTION
The value of function is the functional value of name in the current lexical environment.

= functionは現在のレキシカルな環境を持ったnameの関数値を返す。

この環境を引数に渡せる関数、マクロはいくつかある。 ラムダリストキーワードに &environment を持つものがそれで、例えば setf とか push とか。

(arglist 'setf)
;=> (&WHOLE SYSTEM::WHOLE-FORM &REST SYSTEM::ARGS &ENVIRONMENT SYSTEM::ENV)

macroexpand も環境を引数に渡せるが、こちらはなぜか &optional になっている。

(arglist 'macroexpand)
;=> (FORM &OPTIONAL ENV)

2008年12月18日木曜日

おおえまくすよ マクロをつかわないとは なさけない

(require 'cl) は悪なのか?の続き。

気が向いたので軽く調べてみた。

---

GNU Emacs のマニュアルには以下のような注意書きがある。

Common Lisp Extensions Overview
Please note: the CL functions are not standard parts of the Emacs Lisp name space, so it is legitimate for users to define them with other, conflicting meanings. To avoid conflicting with those user activities, we have a policy that packages installed in Emacs must not load CL at run time. (It is ok for them to load CL at compile time only, with eval-when-compile, and use the macros it provides.) If you are writing packages that you plan to distribute and invite widespread use for, you might want to observe the same rule.

どうやら Emacs 実行時の cl パッケージ読み込みは禁止されていて、コンパイル時のマクロ展開に限って読み込みを許可しているらしい。つまり (require 'cl) ではなくて (eval-when-compile (require 'cl)) を使いなさいってことか。

コンパイル時にマクロ展開をしなければならないのは Common Lisp でも同じだから、この点は納得。

the CL functions are not standard parts of the Emacs Lisp name space

これは「名前には接頭辞を付けろ」という elisp のコーディング規則に反しているから関数上書きしないように気をつけてね、そんな意味でしょうか。

んー、名前空間の話は cl パッケージを読み込んだ時点でユーザは承知していると思うんだが。

ありがたいことに elisp のマクロは CL のマクロと(ほぼ)同等の機能があるのだから、マクロによる抽象化によってソースコードが短く、より簡素になるなら利用しない手はない。見やすいコードとそうでないコード、どっちを書きたい?と質問するようなもの。

…というのが自分の意見です。

所詮 .emacs 位しか書いたことのない学生の意見ですから反論は認めます。mew の作者さんのように何かしらの elisp パッケージを作成した方は、きっとこの cl パッケージのおかげで互換性等々に苦労されたんだと思いますし。

まとめ、あるいは教訓:

  • cl パッケージを利用するファイルは、必ずコンパイルして実行時にそれに依存しない形にすること。(eval-when-compile (require 'cl)) 用法用量を守って正しく使いましょう。
  • マニュアルはなるべく最新のものを参照すること。OSS のマニュアルの邦訳がメンテナンスされないのはよくある話。

おまけ:

「マクロではなく cl.el の関数群を使いたいときはどうすれば?」と質問された時の Stallman 氏の返事

Installed Lisp packages must not use those functions.

2008年12月7日日曜日

あったら便利だと思う

パス名も setf で変更できたらいいのに

(setf (pathname-type "/home/kosh/foo.l") "lsp")
;=> "/home/kosh/foo.lsp"

パッと思いついたもの。 これだと置換する文字数同じでないとダメだし、ファイル名とディレクトリ名が被ると面倒だなあ。やはり make-pathname だろうか

(and (setf (subseq #1="C:/home/xyzzy/xyzzy.exe"
                   (search (pathname-type #1#) #1#))
           "mp3")
     #1#)
;=> "C:/home/xyzzy/xyzzy.mp3"

[追記] 2008-12-13T20:16:43+09:00

初めから make-pathname 使おうと思わないのはまだCL脳でない証拠か

(make-pathname :defaults "C:/home/xyzzy/xyzzy.exe"
               :type "mp3")
;=> #P"C:\\home\\xyzzy\\xyzzy.mp3"

パスネームの構造をよく知らないんだが、リストもしくは構造体で表現されているならば setf が使えてもいい気がするのになあ こんな感じに

((:device "C")
 (:host nil)
 (:directory ("home" "xyzzy"))
 (:name "xyzzy")
 (:type "exe")
 (:version nil))

ま、あくまでも仮定の話だしね