Hatena::Groupcadr

わだばLisperになる このページをアンテナに追加 RSSフィード

2004 | 12 |
2005 | 01 | 02 | 07 | 10 | 11 |
2006 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2007 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2008 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2009 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2010 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2011 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 11 |

2009-02-28

shibuya.lisp TT#2 無事開催!

| 21:22 | shibuya.lisp TT#2 無事開催! - わだばLisperになる を含むブックマーク はてなブックマーク - shibuya.lisp TT#2 無事開催! - わだばLisperになる

本日企画されていた、shibuya.lisp TT#2が無事開催され、つつがなく閉幕することができました!

参加して頂いた、発表者のみなさま、観覧者の皆様ありがとうございました。

今回残念ながら黒田さんの「Lisp quote, unquote」はustreamで中継できなかったのですが、スライド写真等は観客の皆様が撮影されていて、また、概要もどなたか纏めて下さると思いますので、そちらを期待しています!

「LISPを使ってCより遅いならLISPを使っている意味がない!」

という檄的な言葉が印象的でした(*'-')

また、和田先生にも講演して頂きましたが、探究される姿勢には敬服の念を抱かざるを得ませんでした。

まだまだ、海のものとも山のものともつかないshibuya.lispというイベントで講演して頂け感謝感激です。

今回は既に次回のTT#3が7/4に企画されています。

これからもshibuya.lispが盛り上がって行ったら良いなと思う一日でした。

#系マクロdo篇

| 03:43 | #系マクロdo篇 - わだばLisperになる を含むブックマーク はてなブックマーク - #系マクロdo篇 - わだばLisperになる

先日defun#というインターンされないシンボルを変数に指定した場合、dynamic-extent宣言するものを作成してみましたが、どうも効果が薄いので繰り返しならどうだということで、do版のdo#を作成してみました。

(import 'metabang.utilities:CAR-SAFE)

(defun reduce-unintern-sym (sym expr wo)
  (subst sym sym
         expr
         :test (lambda (x y)
                 (and (symbolp y)
                      (not (symbol-package y))
                      (not (member y wo))
                      (string= x y)))))

(defmacro do# (varlist test &body body)
  (let ((syms (remove-duplicates
               (remove-if #'symbol-package
                          (mapcar #'car-safe varlist))
               :test #'string=)))
    (reduce (lambda (res x)
              (reduce-unintern-sym x res nil))
            syms
            :initial-value
            `(do ,varlist
                 ,test
               ,@(when syms `((declare (dynamic-extent ,@syms))))
               ,@body))))

テスト用関数

(defun test-dyn ()
  (do# ((#:l (list 1 2 3 4) (cdr #:l)))
       ((endp #:l) 'foo)
    #:l))

;=> 展開
;(DO ((#:L (LIST 1 2 3 4) (CDR #:L)))
;    ((ENDP #:L) 'FOO)
;  (DECLARE (DYNAMIC-EXTENT #:L))
;  #:L)


(defun test-nomal ()
  (do ((l (list 1 2 3 4) (cdr l)))
      ((endp l) 'foo)
   l))

速度比較 (SBCL 1.0.25/64bit Linux)

(loop :repeat 10000000 :do (test-nomal))
;=> NIL
----------
Evaluation took:
  1.084 seconds of real time
  1.110000 seconds of total run time (1.040000 user, 0.070000 system)
  [ Run times consist of 0.400 seconds GC time, and 0.710 seconds non-GC time. ]
  102.40% CPU
  2,596,046,391 processor cycles
  640,211,664 bytes consed
  
(loop :repeat 10000000 :do (test-dyn))
;=> NIL
----------
Evaluation took:
  0.250 seconds of real time
  0.250000 seconds of total run time (0.250000 user, 0.000000 system)
  100.00% CPU
  599,344,623 processor cycles
  255,024 bytes consed

あまり意味のない空ループを猛烈に回したりすると違いはでるようですが、普通に使うところでは殆ど差は出てこないみたいです(笑)

2009-02-24

今日の発見 2

| 01:00 | 今日の発見 2 - わだばLisperになる を含むブックマーク はてなブックマーク - 今日の発見 2 - わだばLisperになる

前回キーワードに関数を付けてみましたが、他の定数はどうなんだろうということで試してみました。

(defun t (n) n)

(t 3)
;=> 3

なるほど、パッケージロックの警告を貰いますが、破ればOKみたいです。

(defun nil (n) n)

(nil 3) ;=> 3

なるほど、なるほど。

nilは警告がでないのはどうしてでしょう。*1

(() 3) ;=> 3

これはwww

(setf (symbol-function ()) #'funcall)

(() ((lambda (f) (lambda (n) (() f f n)))
     (lambda (f n)
       (if (zerop n)
           1
           (* n (() f f (- n 1))))))
 10)
;=> 3628800
((#|関数名の内部にコメントが書けるのは画期的|#) '+ 3 3)
;=> 6

今日の発見

| 00:42 | 今日の発見 - わだばLisperになる を含むブックマーク はてなブックマーク - 今日の発見 - わだばLisperになる

LISPをみんなで勉強しよう! : 束縛されている?

を読んでいて、おおそういえば、

(boundp :foo)
;=> T

なんだね、という話をLingrのCommon Lisp部屋でしていたのですが、

じゃあ、他のセルはどうなんだろうということで試してみたところ

(fboundp :foo) ;=> NIL

(symbol-value :foo) ;=> FOO

(setf (symbol-plist :foo) 'foo)

(setf (get :foo 'foo) 3)
(get :foo 'foo);=> 3

(symbol-plist :foo) ;=> (FOO 3)

(setf (symbol-function :foo) (lambda (x) x))

(:foo 3) ;=> 3

(defun :bar (n)
  n)

(:bar 3) ;=> 3

(funcall #':bar 3)
;=> 3

(flet ((:quux (n) n)) (:quux 8))
;=> 8

あれ、普通に、:barみたいな関数が作れるじゃないですか!

ずっと知りませんでした。

:barは、keyword:barという関数を定義していることになるのですが、変数セルは変更できなくても他には値を格納できるんですね。

exportしなくても、どのパッケージからも使えたりするんですが、これは禁断の技なのでしょうか。

*1:Tを定義したときにロックを破っていたようです

2009-02-23

書評:Common Lisp: the Reference

| 00:41 | 書評:Common Lisp: the Reference - わだばLisperになる を含むブックマーク はてなブックマーク - 書評:Common Lisp: the Reference - わだばLisperになる

今回は最近買った、Common Lisp: the ReferenceというCLtL1時代のリファレンスです。

当時は、CLtLのように、CLtRと略されていたようです。

Common Lisp: The Reference

LISP処理系CLtL1 ※ANSI Common Lispではありません

Amazonで900ページの本が980円だったので何となく特する気がしてしまい、いらないのに買ってしまいました。

今、4500円位みたいですが、マニアでもない限り4500円で買う価値はないかなと思います。CLtL1の本ですので精々1000円位ではないでしょうか。

特長としては、アルファベット順に並んでいるところがあるかと思います。

適当にページを開いて適当に眺めていると、こんな関数があったのかという発見があったりします。

また、各項目には殆どコードの例が付いているのですが、気の効いた例が多くて感心することが多いです。

さらに、formatや、defstructのオプションでは、オプションごとに解説が載っていたりして、なかなか行き届いた作りになっています。

残念なところは、やはり、CLtL1というところで、「おお!、こんな関数があったのか!」と思ってHyperSpecを引くとANSIでは廃止されたものだったりします。(例えば、commonpなど)

かなり前から出版予告がされているにもかかわらず、さっぱり出る気配のないDavid Margolies氏のThe ANSI Common Lisp Reference Bookですが、CLtRの様な体裁ならば、なかなか面白いものになるのではないかと思いました。

ちなみに、このCLtRですが、昔のAllegro CLには電子版が付属していて、clmanと呼ばれ、Emacsからも簡単に引けるようになっていたようです。

clmanでちょっと古いサイトを調べたところ、この電子版もみつけることができました。これは、UNIXのmanページのような体裁になっていて、大体CLtRと同じ内容のものが、ぱっと引けて便利です。

またEmacsから引けるようなelispですが、元は、ELIのもので、こちらもちょっと手直ししたところ使えるようになりました。

しかし、ライセンス的にどうなんだろうというところがありますので紹介は控えておきます。

clmanでググればすぐ見付けられると思います。

2009-02-22

#系マクロを考える

| 14:14 | #系マクロを考える - わだばLisperになる を含むブックマーク はてなブックマーク - #系マクロを考える - わだばLisperになる

先日defmacro#という、defmacro!の応用マクロを考えてみましたが、以前に、iglambdaという、これも、#:fooのようなシンボルを利用したマクロを考えていました。

このインターンされないシンボルを利用する路線で色々考えてみました。

let#

destructuring-bindに引数のignore宣言を追加してみました。名前が長いので、letに。#が付いていれば、競合することもないでしょう。

(let# (#:a b &rest #:rest) '(1 2 3 4)
  (list b))
;=> (2)

bind#

multiple-value-bind版です。

(bind# (#:s m #:h #:d #:mo y) (decode-universal-time (get-universal-time))
  (list m y))
;=> (52 2009)

lambda#

以前のiglambdaです。致し方ないとはいえ、funcallしないといけないのが残念。

(mapcar (lambda# (#:x) (gensym))
        '(1 2 3 4 5))
;=> (#:G794417 #:G794418 #:G794419 #:G794420 #:G794421)

(funcall (lambda# (#:a b c) (list b c)) 1 2 3)
;=> (2 3)

defun#

defunでも何かできないかと考えたのですが、引数を無視する需要もあまりないかなと思ったので、dynamic-extent宣言することにしてみました。

今のところ&restのみです。&rest# fooでなく、&rest #:fooの方が良いかも。

(defun# add (&rest# x)
  (apply #'+ x))

(add 1 2 3)
;=>  6

定義

(defmacro lambda# ((&rest bvl-spec) &body body)
  (let ((ignores (remove-if #'symbol-package bvl-spec)))
    `(lambda ,bvl-spec 
       ,@(when ignores `((declare (ignore ,@ignores))))
       ,@body)))

(defmacro bind# (bvl-spec values &body body)
  (let ((ignores (remove-if #'symbol-package bvl-spec)))
    `(multiple-value-bind ,bvl-spec ,values
       ,@(when ignores `((declare (ignore ,@ignores))))
       ,@body)))

(defmacro let# (bvl-spec values &body body)
  (let ((ignores (remove-if #'symbol-package bvl-spec)))
    `(destructuring-bind ,bvl-spec ,values
       ,@(when ignores `((declare (ignore ,@ignores))))
       ,@body)))

(defmacro defun# (name lambda-list &body body)
  (flet ((&rest#-p (x) (string-equal '&rest# x)))
    (let ((dynamic (second (member-if #'&rest#-p lambda-list))))
      `(defun ,name ,(substitute-if '&rest #'&rest#-p lambda-list) 
         ,@(when dynamic `((declare (dynamic-extent ,dynamic))))
         ,@body))))

2009-02-21

Emacs Lispで覚えられないところ

| 20:54 | Emacs Lispで覚えられないところ - わだばLisperになる を含むブックマーク はてなブックマーク - Emacs Lispで覚えられないところ - わだばLisperになる

自分がelispですぐ忘れてしまうところに、(interactive)の引数の"P"とか、"r"が何を表わしていたのか、というのがあります。

それと、それとは別ですが、defunの中にある(interactive)というのがCommon Lispに慣れると違和感があるというか、コマンドを定義しているのか、関数を定義しているのかを分けて欲しいなという気がだんだんしてきました。

ということで、だったら、コマンド定義は別にマクロを書けば良いんじゃないかと思って、そんなマクロを書いてみました。

;; Emacs lisp
(defmacro define-command (name type args &rest body)
  (let ((type (case type
                (:numeric "p")
                (:numeric/raw "P")
                (:region "r")
                (otherwise type))))
    `(defun ,name ,args
       (interactive ,type)
       ,@body)))

使用例

;; Emacs lisp
(define-command hello :region (start end)
  (message (format "%d, %d" start end)))

(define-command foo :numeric (n)
  (message (format "%d" n)))

(define-command bar :numeric/raw (n)
  (message (format "%s" n)))

interactiveの取る引数は複数ミックスもできるようなのでこのままでは駄目ですが、こういう方が"p"とか"P"とか、"B"とかよりは忘れにくいかなあとは思いました。

もうちょっと考えてみたいと思います。

2009-02-19

defmacro!に対抗してdefmacro#

| 17:23 | defmacro!に対抗してdefmacro# - わだばLisperになる を含むブックマーク はてなブックマーク - defmacro!に対抗してdefmacro# - わだばLisperになる

自分的には、Let Over Lambdaで最も使えるマクロは、defmacro!に思えますが、この路線を一歩進めて、o!fooや、g!fooという名前でgensymへ置換するシンボルを表わすのではなくて、インターンされない、#:fooのようなシンボルで表現してみました。

インターンされてないシンボルの場合、字面が同じでも同じシンボルではないのですが、この特徴が生きているところ(g!fooとo!fooを使い分けなくて良い)もあれば、これが問題になり対策をしているところもあります(reduce-unintern-sym)。

ごちゃごちゃしているものの、なんとなく自分の意図したものはできました。

しかし、自分で作っておきながらなんですが、なんか怪しいのであまり使おうとは思いません(笑)

(import 'mycl-util:flatten)

(defun reduce-unintern-sym (sym expr wo)
  (subst sym sym
         expr
         :test (lambda (x y)
                 (and (symbolp y)
                      (not (symbol-package y))
                      (not (member y wo))
                      (string= x y)))))

(defmacro *defmacro/# (wo name args &rest body)
  (let ((syms (remove-duplicates
               (remove-if #'symbol-package
                          (flatten body))
               :test #'string=)))
    `(defmacro ,name ,args
       (let ,(mapcar
              (lambda (s)
                `(,s (gensym ,(symbol-name s))))
              syms)
         ,@(reduce (lambda (res x)
                     (reduce-unintern-sym x res wo))
                   syms
                   :initial-value body)))))

(defmacro defmacro# (name args &rest body)
  (let* ((os (remove-if #'symbol-package args))
         (gs (mapcar #'copy-symbol os)))
    `(*defmacro/# ,os ,name ,args
       `(let ,(mapcar #'list (list ,@gs) (list ,@os))
          ,(progn ,@body)))))

動作

(defmacro# square (#:x)
  `(* ,#:x ,#:x))

;; 展開
(let ((x 3))
  (square (incf x)))
;=>
(LET ((X 3))
  (LET ((#:X2531 (INCF X)))
    (* #:X2531 #:X2531)))

2009-02-18

Slimy hackathonへの道(2)

| 04:47 | Slimy hackathonへの道(2) - わだばLisperになる を含むブックマーク はてなブックマーク - Slimy hackathonへの道(2) - わだばLisperになる

Slimy hackathonについてあれこれ考えています。

色々考えているのですが、セッション形式にしたら面白いかなと思ったりしています。

Wiki等でセッションを管理(といっても参加表明くらい)したらどうでしょう。

自分が考えたセッションはこんな感じです。

もちろん自分は全部に参加します(笑)

2009 上半期のSLIMEの設定はこれだ!

利用形態に合わせて最短の設定を探る!

SLIME、Lispマシン化計画

Symbolicsや、TI Explorerのマニュアルを眺めつつSLIMEをLispマシン風に近付ける!

とりあえずキーバインドから!

そしてそれだけなのかもしれない!

SLIME拡張elisp

Pareditや、Redshank等便利に組み合わせられるものを探したり設定を探ったり、自作のelispを紹介したり作ったりする!

逆引きSLIME

逆引きSLIME作る!

逆引きCLにSLIMEの項目はあるので追記とか?

色々な処理系でSLIME

ClojureでSLIME

RubyでSLIME

SchemeでSLIME

etc

色々な処理系でSLIME動かす!

Clojureとか、Dylanなら何か自分も情報提供できるかも!

slime-jp@redit

reditでslime-jpというチャンネルを作成し情報を投下しまくる!

はてぶや、deliciousでも良いかもしれない

どっちが良いのか。

2009-02-16

Slimy hackathonへの道(1)

| 03:57 | Slimy hackathonへの道(1) - わだばLisperになる を含むブックマーク はてなブックマーク - Slimy hackathonへの道(1) - わだばLisperになる

私の考えるHackathon

昨日Smiley Hackathon#4に参加させて頂いたお蔭さまで、実際にLISPをお題にHackathonを開催するとしたらどうなるかが、なんとなく想像できました。

自分が勝手に抱いているHackathonのイメージ的には、Hackathonは長くなくちゃいけないんじゃないかというのがあります。

とにかく長くて疲れる。

そうなってくると、やはり、24時間以上で開催したいですよね。

開催時間

それで、24時間以上となると、24時間では嫌に現実的な時間であり、ずっと起きてなくちゃいけなそうなところがありしんどそうなので、若干、現実味を失なった48時間はどうかと思いました。

マラソンなので、42.195時間でも良いんじゃないかとも思っています。

すること

SLIMEがお題なわけですが、この48時間で一体何をするのかを考えてみます。

  1. 様々な処理系で、SLIMEが動くか試す/Tipsをまとめる
  2. SLIMEを初めて使ってみる/質問する/答える
  3. 今迄使っているSLIMEの環境をもっと便利にする拡張を書く/情報を探してまとめる

といった位かなと思います。

先日の2/14にswank.rbというRuby用のものが出たりしてRubyの方がSlimy Hackathonに参入して貰える可能性も出てきました。

もういちど、SLIME(SWANK)が動く処理系を挙げてみます。

  1. Common Lisp色々
  2. MIT Scheme
  3. Dylan
  4. Scheme 48
  5. Clojure
  6. GOO
  7. jolt
  8. Kawa
  9. Ruby

開催場所

48時間の会場を確保するのはほぼ無理なのでとりあえず、オンラインで開催かなと思います。

Lingr部屋か、IRCチャンネルを設けて共有レポジトリとWikiを作成し、皆でコミットしたりリソースを収集しまくります。また、Skypeの利用も検討できるでしょう。

そもそも、48時間は長いので、どういう運営にしようか、というところから考えても良いかもしれません。

開催日時

具体的な日時は決まっていませんが、それなりに現実的にしようと思うと、金曜の夜開始で、日曜の夜終了という風になるかと思います。

例えば、金曜の21時開始→日曜の21時終了です。

参加形態

とりあえず、長い人生の中でほんの48時間という枠組でSLIMEというテーマのもとに活動すれば良いことにし、適当に24時間TVを見たり見なかったりする如くゆるく参加できれば良いのかなと思います。

気分的には、2/20-2/22で開催したいと思っていますが、急すぎる気もします。

3/6-3/8等も良いと思っています。

問題点

割と私は盛り上がってきているのですが、賛同を得られるかどうかというのが最大の問題です(笑)

2009-02-15

第4回Smiley Hackathon(仮)に参加してきました!

| 22:49 | 第4回Smiley Hackathon(仮)に参加してきました! - わだばLisperになる を含むブックマーク はてなブックマーク - 第4回Smiley Hackathon(仮)に参加してきました! - わだばLisperになる

昨日2/14日に、Smiley Hackathon(仮)に参戦してきました。

総勢、15、6名の参加だったと思いますが、Perlの方が殆どで、Lisperしか知らない自分には新鮮でした!

今回の自分のテーマは、以前にちょっと作っていたCLOSでMoose風の構文を真似るというものでしたが、割と話に熱中していたのでコードは書けてませんでした(笑)

以前のものからあまり進んでませんし、その場しのぎでごちゃごちゃ追加しただけですが、一応貼っておきます。

次回に参加する時は、スロットの遅延評価機能を付けたいです。

(defpackage :moose
  (:use :cl))

(in-package :moose)

(defpackage :moose
  (:use :cl))

(in-package :moose)

(eval-when (:compile-toplevel :load-toplevel :execute)
  (defun get-hases (attributes)
    (remove :has attributes :key #'car :test-not #'eq))
  
  (defun get-subs (attributes)
    (remove :sub attributes :key #'car :test-not #'eq))
  
  (defun ensure-has-attributes (class-name attributes)
    (declare (ignore class-name))
    (mapcar (lambda (x)
              (let ((has (getf x :has))
                    (is (getf x :is))
                    (isa (getf x :isa)))
                `(,has
                  ,@(and is (list 
                             (case is
                               (rw :accessor)
                               (ro :reader)
                               (otherwise (error "malformed attributes")))
                                        ;(intern (format nil "~:@(~A.~A~)" class-name has))
                             has
                             ))
                  ,@(and isa (list :type isa)))))
            (get-hases attributes)))
  
  (defun ensure-sub-attributes (class-name attributes)
    (mapcar (lambda (x)
              (let* ((args (cdr x)))
                `(defmethod ,(first args) ((self ,class-name) ,@(second args)) ,@(cddr args))))
            (get-subs attributes)))
  
  (defun get-afters (attributes)
    (remove :after attributes :key #'car :test-not #'eq))

  (defun get-befores (attributes)
    (remove :before attributes :key #'car :test-not #'eq))

  (defun get-arounds (attributes)
    (remove :around attributes :key #'car :test-not #'eq))

  (defun ensure-after-attributes (class-name attributes)
    (mapcar (lambda (x)
              (let ((args (cdr x)))
                `(defmethod ,(first args) :after ((self ,class-name) ,@(second args)) ,@(cddr args))))
            (get-afters attributes)))

  (defun ensure-before-attributes (class-name attributes)
    (mapcar (lambda (x)
              (let ((args (cdr x)))
                `(defmethod ,(first args) :before ((self ,class-name) ,@(second args)) ,@(cddr args))))
            (get-befores attributes)))

  (defun ensure-around-attributes (class-name attributes)
    (mapcar (lambda (x)
              (let ((args (cdr x)))
                `(defmethod ,(first args) :around ((self ,class-name) ,@(second args))
                   (macrolet ((super (&rest args)
                                `(call-next-method ,@args)))
                     ,@(cddr args)))))
            (get-arounds attributes))) )

(defmacro defmoose (name (&rest extends) &rest attributes)
  `(progn
     (defclass ,name ,extends
       ,(ensure-has-attributes name attributes))
     ,@(ensure-sub-attributes name attributes)
     ,@(ensure-after-attributes name attributes)
     ,@(ensure-before-attributes name attributes)
     ,@(ensure-around-attributes name attributes)))

;; new
(setf (fdefinition 'new)
      (fdefinition 'make-instance))
>describe
;#<POINT {100DB9CF81}> is an instance of class #<STANDARD-CLASS POINT>.
;The following slots have :INSTANCE allocation:
; X    30
; Y    0

(defmoose point-3d (point)
  (:has z :is rw)
  (:after clear ()
          (setf (z self) 0)))

(let ((p (make-instance 'point-3d)))
  (clear p)
  (setf (x p) 30)
  p)

;>>describe
;#<POINT-3D {100E1D9431}> is an instance of class #<STANDARD-CLASS POINT-3D>.
;The following slots have :INSTANCE allocation:
; X    30
; Y    0
; Z    0
;; メソッド結合 before after

;; プライマリ
(defmoose hello ()
  (:has mesg :is rw)
  (:sub mesg ()
        (format t "~&こんにちは!~%")))

(mesg (new 'hello))
;-> こんにちは!
;=> NIL

;; before追加
(defmoose hello ()
  (:has mesg :is rw)
  (:sub mesg ()
        (format t "~&こんにちは!~%"))
  (:before mesg ()
           (format t "~&あー、テステス~%")))

(mesg (new 'hello))
;-> あー、テステス
;   こんにちは!
;=> NIL

;; after追加
(defmoose hello ()
  (:has mesg :is rw)
  (:sub mesg ()
        (format t "~&こんにちは!~%"))
  (:before mesg ()
           (format t "~&あー、テステス~%"))
  (:after mesg ()
          (format t "~&さようなら~%")))

(mesg (new 'hello))
;-> あー、テステス
;   こんにちは!
;   さようなら
;NIL

;; メソッド結合 around

;; プライマリ
(defmoose around-hello ()
  (:has mes :is rw)
  (:sub mes ()
        (format t "~&こんにちは!~%")))

(mes (new 'around-hello))
;-> こんにちは!
;=> NIL

(defmoose around-hello ()
  (:has mes :is rw)
  (:sub mes ()
        (format t "~&こんにちは!~%"))
  (:around mes ()
           (format t "~&** ご紹介します! **~%")
           (super)                      ;プライマリを呼ぶ
           (format t "~&** ありがとうございました! **~%")))

(mes (new 'around-hello))
;-> ** ご紹介します! **
;   こんにちは!
;   ** ありがとうございました! **
;=> NIL

2009-02-11

Slimy Hackathon(仮)がやりたい

| 17:33 | Slimy Hackathon(仮)がやりたい - わだばLisperになる を含むブックマーク はてなブックマーク - Slimy Hackathon(仮)がやりたい - わだばLisperになる

今週末に自分は、no titleに参加を表明しているのですが、非常にベタなオマージュのですが、Slimy Hackathon(仮)をやってみるのはどうかと思いました。

SLIMEでなんかするハッカソンです。

「こんな機能を発見した!」「○○したい場合には、どうやれば良いのか!」「こんな拡張はどうか!」というのを延々とやる会です。

対象の処理系としては、Common Lispはもとより、Scheme、Clojure、GOO、JOLT、Dylan、Kawaと色々あります。

開催場所が問題になるのですが、物理的に集合する場合、どこか8時間位開場を貸して頂ける優しい方/企業さまを探す必要があります。

物理移動は面倒なのでSkypeでチャットしながらCodeReposにコミットというのも良いかもしれません。

ということで、atnd.orgを使ってみたかったので、イベントを作成してみました。

コメントできるみたいなので良かったらコメント/アイディアの投稿/開場提供情報等々お待ちしています。

2009-02-09

(declare (ignore ignore))が面倒

| 15:20 | (declare (ignore ignore))が面倒 - わだばLisperになる を含むブックマーク はてなブックマーク - (declare (ignore ignore))が面倒 - わだばLisperになる

最近は専らClozure CLばかり使っているのですが、ふとしたきっかけから

(declaim (ignore ignore))

が動くことを知りました。

これで、大域的にdeclaimや、proclaimで変数ignoreを無視する宣言ができたら

(let ((foo '(a b c d e f g)))
    (mapcar (lambda (ignore) (gensym))
            foo))

などでもLAMBDAのところにdeclareを入れなくて済むのでイイ! などと思っていたのですが、SBCLにしたら普通に警告がでたので、HyperSpecで調べたら、どうもdeclaim/proclaimでignoreが使えるのは、Clozure CLの拡張のようです。

そうなると、やっぱりマクロしかないかということで、ちょっと工夫したマクロを考えてみました。

ちょっとの工夫とは、変数にインターンされない変数を利用した場合は、自動的にそれが無視リストに加えられるというものです。

名前はともかくとして、インターンされない変数名を利用すると同じ名前が並べられるので割と使い勝手は良いかもと思いました。

igmultiple-value-bindなどの派生も考えられます。

(defmacro iglambda ((&rest bvl-spec) &body body)
  (let ((ignores (remove-if #'symbol-package bvl-spec)))
    `(lambda ,bvl-spec 
       (declare (ignore ,@ignores))
       ,@body)))
(let ((foo '(a b c d e f g)))
  (mapcar (iglambda (#:ignore #:ignore) (gensym))
          foo
          foo))
;=> (G2742 G2743 G2744 G2745 G2746 G2747 G2748) 

(funcall (iglambda (#:x) (print "foo")) 33)
;-> "foo"
;=> "foo"

2009-02-07

書評:Lispプログラミング入門 (KE養成講座)

| 09:59 | 書評:Lispプログラミング入門 (KE養成講座) - わだばLisperになる を含むブックマーク はてなブックマーク - 書評:Lispプログラミング入門 (KE養成講座) - わだばLisperになる

そういえば自分はこのブログに書評とか書いたことが無いことに気付きました。

考えてみるにLISP関係の本は絶版になることも多く、一体どんな本なのかがamazonでレビューされることも少ないと思うので、どんなものであれ書評があると少しは役に立つのかなと思えてきました。

ということで、昨日、図書館から借りた「Lispプログラミング入門 (KE養成講座)」を読み終えたので感想を書いてみます。

Lispプログラミング入門 (KE養成講座)

LISP処理系CLtL1 ※ANSI Common Lispではありません

著者の白川洋充氏は、70年代からLISPをのスタンフォード大でAI研究もされていた方のようで、CLについて考察が、それまでのLISPとの比較から語られていたりして面白いです。

また、内容が現在の一般的な入門書からするとちょっと変っていて、アレイについて:displaced-to とかの使い方がそれなりに詳しく解説されていたり、継続渡しの解説(関数を渡すのではなくラムダ式を組み立ててゆく方式)があったり、それを利用して、探索、バックトラッキングの説明へと続いたりします。

面白かったところ

あまり本文とは関係のないところなのですが、setfにapplyを適用できない代わりの方法として、setfでapplyを使う方法が紹介されていました。

(let ((a #2a((1 2 3) (4 5 6) (7 8 9)))
      (pos '(1 1)))
  (setf (apply #'aref a pos) 'foo)
  a)
;=> #2A((1 2 3) (4 FOO 6) (7 8 9))

なるほど、これは知りませんでした。

そもそもの発端を考えると、setfにapplyを適用したかったということなのですが、ANSI Common Lispだと

(let ((a #2a((1 2 3) (4 5 6) (7 8 9)))
      (pos '(1 1)))
  (apply #'(setf aref) 'foo a pos)
  a)
;=> #2A((1 2 3) (4 FOO 6) (7 8 9))

とも書けますね。しかし、上のものの方が分かり易いと思います。

それと、まったくどうでも良いところなのですが、本著作中では、LAMBDAの引数に、Uや、Vが使われています。

(lambda (u v) (list u v ..))

どういう由来なのかは分からないのですが、昔のコードを眺めると、MITのLISPだと、XとかYなのですが、スタンフォードのLISPだと、UとかVなんですよね。

そんなところにスタンフォード大の香りを感じました(笑)

絶版ですが、ヤフオクや古本屋で見かけたら保護したい本です。

2009-02-06

インターンされないシンボルとGENSYM (2)

| 04:34 | インターンされないシンボルとGENSYM (2) - わだばLisperになる を含むブックマーク はてなブックマーク - インターンされないシンボルとGENSYM (2) - わだばLisperになる

「インターンされないシンボルとGENSYM」についてkozimaさんとNANRIさんから興味深いコメント頂きました!

kozimaさん:

1=#:hoge は、xyzzy のソースでは使われてます。が、他では見かけませんね。そんなに問題になるような状況は思いつかないのですが……。

一応、(function-lambda-expression (macro-function 'my-dotimes)) でソースを取り出して分解していけば捕捉できなくもないでしょうが、さすがにそこまで気にすることはないんじゃないかと思いますし。

おお、xyzzyでそういう記述があるとは知りませんでした!

また、FUNCTION-LAMBDA-EXPRESSIONで取り出すということで、どうにかして取り出した場合の問題を考えてみたのですが、

(defmacro foo ()
  (let ((sym '#:foo))
    `(progn ',sym)))

(eq (foo) (foo))
;=> T

(defmacro foo2 ()
  (let ((g (gensym)))
    `(progn ',g)))

(eq (foo2) (foo2))
;=> nil

(defmacro foo3 ()
  (let ((sym (make-symbol "FOO")))
    `(progn ',sym)))

(eq (foo3) (foo3))
;=> nil

というところで、'#:fooは展開の度にシンボルを生成していないことで何らかの捕捉を引き起こす可能性が高くなるのかなと思えました。

無理矢理ですが、

(defmacro bar ()
  (let ((sym '#:bar))
    `(locally
         (declare (special ,sym))
       ',sym)))

(set (bar) 3)
(symbol-value (bar))
;=> 3

(defmacro bar2 ()
  (let ((sym (gensym)))
    `(locally
         (declare (special ,sym))
       ',sym)))

(set (bar2) 3)
(symbol-value (bar2))
;=> unbound error

(defmacro bar3 ()
  (let ((sym (make-symbol "BAR")))
    `(locally
         (declare (special ,sym))
       ',sym)))

(set (bar3) 3)
(symbol-value (bar3))
;=> unbound error

など。もっとまともな局面がありそうですが、これくらいしか思い付きませんでした(^^;

NANRIさん:

「#:」も「#=」もリーダーマクロなのでreadtableが変な風にいじられていたらダメなんでしょうが、これも気にし過ぎのような気がします。

なるほど、確かに!

(set-macro-character #\# nil)

等とすると

(progn '#:bar)

は、#なんてパッケージはない!というエラーになってしまいますが、GENSYMや、MAKE-SYMBOLは普通に動きます。

また、#:の定義を追い掛けてみたところSBCLでは、MAKE-SYMBOLを呼びだすものになっていました。

他の処理系では、どういう風に定義されているかは調べていないのですが、#:は、MAKE-SYMBOL+αのリーダーマクロと考えていてもそんなに問題はなさそうです。

そうなると、表示されてくる#:は、なんなのだということになりますが、

(setq *print-gensym* nil)

で消せるので、読み書きで統一感を持たせるためのものなのかもしれません。#()もそんな感じですね。

まとめ

'#:fooだと弱いかもしれませんが、MAKE-SYMBOLなら大丈夫なのかもしれません。

しかし、MAKE-SYMBOLだと入力が長くて面倒ですね。

ということで、みんな故郷のGENSYMに帰って行くのかもしれません(笑)

2009-02-05

第4回Smiley Hackathon(仮)に参加してみることにしました!

| 12:14 | 第4回Smiley Hackathon(仮)に参加してみることにしました! - わだばLisperになる を含むブックマーク はてなブックマーク - 第4回Smiley Hackathon(仮)に参加してみることにしました! - わだばLisperになる

以前から、Smiley Hackathon(仮)って面白そうだなと思っていたのですが、今回は参加してみることにしてみました。

自分は、前に作ったCLでMooseの続きを作ったりしたいと思っています。(会場がPerlな雰囲気なので)

まだ定員に10名位の余裕はあるようです。

折角なのでどなたか一緒にMooseマクロを作りませんか!

インターンされないシンボルとGENSYM

| 11:01 | インターンされないシンボルとGENSYM - わだばLisperになる を含むブックマーク はてなブックマーク - インターンされないシンボルとGENSYM - わだばLisperになる

Common Lispでは、インターンされないシンボルは、#:fooのように書くことができて、これはリードの度に新しいシンボルになるので同名でも同じシンボルではありません。

そう考えると例えば、my-dotimesを定義するとして

(defmacro my-dotimes ((var times &optional result)
                      &body body)
  (let ((limit (gensym)))
    `(do ((,limit ,times)
          (,var 0 (1+ ,var)))
         ((<= ,limit ,var) ,result)
       ,@body)))

と書いているgensymは別に毎回違う名前を生成する必要はないんじゃないかと思えて来ました。

つまり

(defmacro my-dotimes ((var times &optional result)
                      &body body)
  (let ((limit '#:limit))
    `(do ((,limit ,times)
          (,var 0 (1+ ,var)))
         ((<= ,limit ,var) ,result)
       ,@body)))

で良いのではないかと。(make-symbol "LIMIT")でも良いでしょう。

更に、同じシンボルを指せれば良いので

(defmacro my-dotimes ((var times &optional result)
                      &body body)
  `(do ((#1=#:limit ,times)
        (,var 0 (1+ ,var)))
       ((<= #1# ,var) ,result)
     ,@body))

とも書けるでしょう。

展開結果は、

(let ((foo 10))
  (my-dotimes (i (incf foo) (progn 
                              (write i)
                              (terpri)))
    (write i)))

;; %=>
(DO ((#:LIMIT (INCF FOO))
     (I 0 (1+ I)))
    ((<= #:LIMIT I) (PROGN (WRITE I) (TERPRI)))
  (WRITE I))

のような感じです。

展開結果で、#:g0001等になるより読みやすく、(gensym "LIMIT")などとするより面倒でなく読みやすいという感じなのですが、#:fooの表記を使うと何か致命的な問題があったりするのでしょうか。

例えば、symbol-nameで判定してなにかすると、キャプチャできてまずい、とか。しかしその場合、GENSYMでも恐らく問題はありかなと。

CLより前は、#:という記法がなかったよう(少なくともMacLISPにはない様子)なので、GENSYMを利用する必要があります。

ちなみにGENSYMは同じ名前にすることができて

(gensym 100)
;=> #:G100

とすれば、いつでも#:G100が返りますが、当然ながらこれもEQになりません。

しかし、名前が被ろうが被るまいが、インターンされないシンボルはなんにしろ互いにEQになりません。

MacLISPの時代は、インターンされないシンボルを記述する一番手軽な方法は、GENSYMのようですが、GENSYMを利用する必要が無くなってもMacLISPから続く伝統がそのまま受け継がれていたりするのでしょうか。真相や如何に。

2009-02-04

CLでぱっとしない関数

| 00:07 | CLでぱっとしない関数 - わだばLisperになる を含むブックマーク はてなブックマーク - CLでぱっとしない関数 - わだばLisperになる

CLでは、別に不便というわけでもないのに、あまりぱっとしない関数があるように思えます。

例えば、write

(let ((*print-base* 16))
  (prin1 22))

とか書くなら

(write 22 :base 16)

と書けますし、write単体でも、prin1とかいう名前より馴染み深いと思うのですが、あまりぱっとしません。

自分のなかでは、writeは何故かプリミティブなものという印象があります。

その他だと、map。

mapは、リストだけでなくシーケンス全般に使えて、結果の型も指定できるので割と万能なやつなのですが、リストなら、mapcarですし、アレイなら、loopというところで、これもぱっとしません。

(map nil (lambda ...)
  ...)
;=> nil

とかにすると、最後にnilを返すことで副作用目的ですよ、ということを主張できる気がして好きなんですが、汎用だけに遅かったりするのかしらとか思うと、

(progn
  (mapc (lambda ...)
    ...)
 nil)
;=> nil

なんて書いてしまうわけですね。実際、こういうコードの方が多いですし。

というかこの場合はmapcの返り値にも問題があるわけですが。

あとは強いて挙げるなら、elt。

elementの略だというのがわかりづらい名称でシーケンス全般から要素を取り出す汎用的なものですが、遅いというイメージを持たれているのか、専用関数に置き換えられることが多いようです。

しかし、Lispマシンのマニュアルによると、タグマシンだと型はハードウェアで区別できるので、eltも専用関数も効率は変わらないという説明があったりします。ビバLispマシン。

そういうことを聞くとできるだけ汎用的な関数を使いたくなってしまいます。

ということで、elt vs aref、elt vs nthを比較してみましたが、SBCLやSCLだと殆ど差はないようです。

しかし、Clozure CLだと実に20倍の速度差。

こういう例があるとやっぱり使い分けとか言われちゃいますよね。

でも、Clozure CL以外は、殆ど速度に変化なしみたいですし、個人的にはeltとかmapとか多用して行きたいかなと思います。

ぱっとしない関数全般に言えるのは、MacLISPに存在せず、Zetalisp後期か、Common Lispになってから導入されたものが多いんじゃないかというところです。逆に置き換えに成功した事例としては、block+tagbody vs progがあるように思えます。ちなみに、そのprogもなくなったわけではありません。

伝統を継承しつつ新しくするというのは、色々大変なのかもしれません。

2009-02-02

「format の痒いのに手が届かないところ」に挑戦!

| 03:49 | 「format の痒いのに手が届かないところ」に挑戦! - わだばLisperになる を含むブックマーク はてなブックマーク - 「format の痒いのに手が届かないところ」に挑戦! - わだばLisperになる

少しブログのトラックバックやコメント機能を活用してみようということで、これからは積極的にトラックバックをしてみることにしました。

今回は、kozimaさんの

を読んでいて、kozimaさんよりナイスな解決法を思い付ける気は全然しませんが、これは面白いと思ったので自分でも色々考えてみました。

まずは、フォーマットストリングではなくてS式だったら良いのでは、というのを受けて関数にしてみたらどうかというところ

fletで

(flet ((format-items (stream arg list)
         (format stream "<ul>~%")
         (dolist (item list)
           (format stream "~VT<li>~A</li>~%" arg item))
         (format stream "</ul>")))
  (format nil #'format-items 3 '(aaa bbb ccc)))
;=>
"<ul>
   <li>AAA</li>
   <li>BBB</li>
   <li>CCC</li>
</ul>
"

formatに直にlambdaを渡す

(format nil (lambda (str n args)
              (format str "<ul>~%")
              (dolist (item args)
                (format str "~VT<li>~A</li>~%" n item))
              (format str "</ul>"))
        3 '(aaa bbb ccc))

やはりいまいちですね。

まったくすっきりする気配がありません。

メソッドにしたらどうか

(defmethod format-ul-method (str n args)
  (dolist (item args)
    (format str "~VT<li>~A</li>~%" n item)))

(defmethod format-ul-method :around (str n args)
  (format str "<ul>~%")
  (call-next-method)
  (format str "</ul>"))

(format nil #'format-ul-method 3 '(aaa bbb ccc))

完全にあさっての方向に進んでしまいましたね。

あさってついでに

(defmethod format-ul-method :around (str n args)
  (format str "<ul>~%~/CALL-NEXT-METHOD/</ul>"))

とかできると面白いかなと思いました。

大域定義にcall-next-methodが存在するかどうかは、処理系依存らしいので、もしかしたらできてしまう処理系もあるのかもしれません。

まとめ

全然まとまってないのですが、やはりformatの~//指示子がローカル関数も対象になると便利かなと思いました。

2009-02-01

第31回慢性的CL勉強会@Lingr8時だョ!全員集合まとめ

| 04:30 | 第31回慢性的CL勉強会@Lingr8時だョ!全員集合まとめ - わだばLisperになる を含むブックマーク はてなブックマーク - 第31回慢性的CL勉強会@Lingr8時だョ!全員集合まとめ - わだばLisperになる

1/31 20:00から31回目の勉強会を開催させて頂きました!

発言して頂いた方約10名、observer(ROM)の方約5名前後で、大体15名前後を推移しつつでした。

今回は、過去30回を振り返るでした。

オンラインでの勉強会の話題、LISP系言語のコミュニティの話題、今後の展望等、話が広がって割と興味深かったと思います。

今回で毎週土曜20時のLingr部屋での勉強会は終了となりますが、有志の皆さんでの何か新しい勉強会の試みが出てくることを期待しています!

ログ:

謝辞:

これまでページへの勉強会のロゴ設置ありがとうございました!

これまで勉強会の一員に加えて頂いてありがとうございました!