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 |

2011-02-19

CREATE-SERVERしたSWANKに接続すると日本語の評価で切断してしまう

| 21:12 | CREATE-SERVERしたSWANKに接続すると日本語の評価で切断してしまう - わだばLisperになる を含むブックマーク はてなブックマーク - CREATE-SERVERしたSWANKに接続すると日本語の評価で切断してしまう - わだばLisperになる

自分は、SLIMEはEmacsから起動しないで別途SWANKサーバーを立ててそこに接続する派なのですが、最近になって日本語を評価すると接続が切断されるという現象に遭遇するようになりました。

*slime-events*を見ると、

(:coding-system "iso-latin-1-unix" :external-format "LATIN-1")

となっていて、UTF-8になっていないのが原因ということは分かりますが、Emacs側のslime-net-coding-systemもutf-8-unixだし、CL処理系のEXTERNAL-FORMATもUTF-8にしているし、どういうことなのかと。

調べてみたところ、SWANK:CREATE-SERVERではcoding-systemが別途指定できるようになっていて、指定がないためデフォルトの指定になっている、ということが分かりました。

ということで、

(swank::create-server :port 4005
                      :coding-system "utf-8-unix"
                      :dont-close 'T)

のようにしたところ問題は解決。

:coding-systemを与えないと、デフォルトでは、SWANK::*CODING-SYSTEM*を参照するようですが、これがiso-latin-1-unixになっているようです。

ということで、こちらをutf-8-unixに変更してもOKです。

2010-10-05

SLIMEばつ牛ン (2) slime-apropos

| 13:00 | SLIMEばつ牛ン (2) slime-apropos - わだばLisperになる を含むブックマーク はてなブックマーク - SLIMEばつ牛ン (2) slime-apropos - わだばLisperになる

SLIMEのコマンドを確認していくシリーズ、今回は、 slime-apropos です。

キーバインド

デフォルトのキーバインドは、c-c c-d c-aもしくは、c-c c-d c-z

最後のc-aと、c-zの違いですが、aの方は、EXPORTされているシンボルのみで、zの方は、すべてのシンボルを対象にします。

使い方

M-x slime-apropos

を実行すると、探したいシンボルの名前を訊かれますので、入力します。(名前の一部でもOKです)

SLIME Apropos: foo
CL-MARKDOWN:FOOTNOTE
  Function: (not documented)
CL-MARKDOWN:FOOTNOTES
  Function: (not documented)
COM.INFORMATIMAGO.COMMON-LISP.HTML:TFOOT
  Macro: (not documented)
COM.INFORMATIMAGO.COMMON-LISP.HTML:TFOOT*
  Function: (not documented)
COM.INFORMATIMAGO.COMMON-LISP.HTRANS:GENERATE-HTML-FOOTER
  Generic Function: A hook allowing the hprogram to display a footer.

という風に候補がでます。

自分はこのslime-aproposで使えそうな関数を探すために可能な限りのパッケージ詰め込んだコアを作成して使っていたりします。

定義は、

(defun slime-apropos (string &optional only-external-p package 
                             case-sensitive-p)
  "Show all bound symbols whose names match STRING. With prefix
arg, you're interactively asked for parameters of the search."
  (interactive
   (if current-prefix-arg
       (list (read-string "SLIME Apropos: ")
             (y-or-n-p "External symbols only? ")
             (let ((pkg (slime-read-package-name "Package: ")))
               (if (string= pkg "") nil pkg))
             (y-or-n-p "Case-sensitive? "))
     (list (read-string "SLIME Apropos: ") t nil nil)))
  (let ((buffer-package (or package (slime-current-package))))
    (slime-eval-async
     `(swank:apropos-list-for-emacs ,string ,only-external-p
                                    ,case-sensitive-p ',package)
     (slime-rcurry #'slime-show-apropos string buffer-package
                   (slime-apropos-summary string case-sensitive-p
                                          package only-external-p)))))

となっています。

定義を眺めていて知ったのですが、数引数を付けるとオプションを全部対話的に処理することができるようです。

指定できるオプションは、

  • 外部シンボルのみかどうか
  • 指定したパッケージ内部で探す
  • 大文字小文字を区別するかどうか

自分は、c-c c-d c-zを知らなかったので、ちょっと不便だなと思っていたのですが、ちゃんと用意されていたんですね。

2010-09-29

SLIMEばつ牛ン (1) slime-eval-defun

| 23:11 | SLIMEばつ牛ン (1) slime-eval-defun - わだばLisperになる を含むブックマーク はてなブックマーク - SLIMEばつ牛ン (1) slime-eval-defun - わだばLisperになる

KMRCLも難しいファイルを後回しにしていたので、だんだん解説が難しくなってきたので、逃げ道の開拓ということで、SLIMEの機能を適当に探ってみることにしました。(LISP365完了の12月まで毎日書けるような軽いネタが必要なため…)

今回は、 slime-eval-defun です。

キーバインド

デフォルトのキーバインドは、c-m-x。

ちなみに私は、c-m-xは押しにくいし、Lispマシンと同じキーバインドにしたかったので、c-sh-e*1にしてみています。

使い方

評価したい式の上で、実行します。

(slime-)eval-defunということで、基本的に関数定義を評価するためのものだと思うのですが、大雑把にフォームを評価するもの、という感じです。

数引数を付けると、結果をバッファ内に挿入してくれるオマケ機能があります。

(+ 3 3 3)
<ここで実行>9

定義は

;; elisp
(defun slime-eval-defun ()
  "Evaluate the current toplevel form.
Use `slime-re-evaluate-defvar' if the from starts with '(defvar'"
  (interactive)
  (let ((form (slime-defun-at-point)))
    (cond ((string-match "^(defvar " form)
           (slime-re-evaluate-defvar form))
          (t
           (slime-interactive-eval form)))))

こんな感じですが、defvarを特別扱いしていて、defvarの場合は、値をセットしなおしてくれるというさらなるオマケ機能があります。

defvarの挙動が面倒でdefparameterにしている人には嬉しい機能ですね。(望んでない人もいるかもしれませんが…)

私は以前、Lispマシンのマニュアルを眺めていて、Evaluate Region Hack(c-m-sh-e)という同様の動きをする関数をみつけて、感心して早速自作してみたことがあったのですが、SLIMEにもあったのを後で知りました。歴史は繰り返すのか、文化が連綿と受け継がれているのか…。

数引数があれば、slime-interactive-evalが呼ばれて、結果としてバッファに評価結果が挿入されます(この辺りを追い掛けて行くと芋蔓できりがなさそうなので、この辺にしておきます…。)

このブログを書いていると評価する式と評価結果を併せて書いたりすることが多いのですが、

(+ 3 3 3)
9

から一歩進んで、

(+ 3 3 3)
;; => 9

としてくれると嬉しいのにな、と思ったりもします。

そんなことをぼやいていたら、quekさんに自作のユーティリティを教えてもらいました。

;; elisp
;; 評価した結果をバッファ内に ;;=> 結果 という形で挿入
;; quekさん作
(defun slime-que-print-last-expression (string)
  "Evaluate sexp before point; print value into the current buffer"
  (interactive (list (slime-last-expression)))
  (insert "\n;; => ")
  (slime-eval-print string))

これは便利ですね!

*1:shはシフト

2010-09-19

簡単なSWANKの拡張で適当補完

| 02:11 | 簡単なSWANKの拡張で適当補完 - わだばLisperになる を含むブックマーク はてなブックマーク - 簡単なSWANKの拡張で適当補完 - わだばLisperになる

slime-complete-formというコマンドがあるのですが、これは文脈に応じて実行すると、

;; ■ = カーソル
(EVAL-WHEN ■)
;->
(EVAL-WHEN (:compile-toplevel :load-toplevel :execute) body...)

と補完してくれるというものです。

そんなに活躍するところもないのですが、ぴったりはまる場所では便利です。(eval-whenとか、(declare (optimize))とか)

そんな slime-complete-form の実装を眺めてみたのですが、なにかを補完したい場合には流用できそうだったので、試しにお決まりのパターンを補完するようなものをでっち上げてみました(コードは文末)

かなり適当なコードですが、

(MAPCAR ■)
;->
(MAPCAR (LAMBDA ()))
(DEFPACKAGE ■)
;->
(DEFPACKAGE :FOO
  (:USE :CL))
(REDUCE #'+ FOO■)
;->
(REDUCE #'+ FOO :INITIAL-VALUE)
(SET-DISPATCH-MACRO-CHARACTER ■)
;->
(SET-DISPATCH-MACRO-CHARACTER #\# #\? (LAMBDA (STREAM SUBCHAR ARG) (DECLARE (IGNORE SUBCHAR ARG)) ))

位のことはできます。

補完した後にカーソルも適切な場所に移動したりできたら、それなりに便利にはなりそうではあります。

ちなみに、SWANKを眺めていたら、パターンマッチのユーティリティが取り込まれていたので使ってみました。

Stephen Adams氏作で、

http://www.cs.cmu.edu/afs/cs/project/ai-repository/ai/lang/lisp/code/match/miranda/select.cl

のものと同一だと思われます。

以前、Chaton COMMON LISP JP部屋でshiroさんにCLを書く時に使っているライブラリを伺ったときに、パターンマッチがないとやってられないので、これを改造して利用していると伺った覚えがあります。

SWANKに付いてくるので、自分がCLを使っている時は常時読み込まれていますし、しばらく積極的に使ってみようかなと思っています。

コード

emacs側
(progn
  (defun slime-my-complete-form ()
    (interactive)
    ;; Find the (possibly incomplete) form around point.
    (let ((buffer-form (slime-parse-form-upto-point)))
      (let ((result (slime-eval `(swank:my-complete-form ',buffer-form))))
        (if (eq result :not-available)
            (error "Could not generate completion for the form `%s'" buffer-form)
          (progn
            (just-one-space (if (looking-back "\\s(" (1- (point)))
                                0
                              1))
            (save-excursion
              (insert result)
              (let ((slime-close-parens-limit 1))
                (slime-close-all-parens-in-sexp)))
            (save-excursion
              (backward-up-list 1)
              (indent-sexp)))))))

  (define-key slime-mode-map [(control ?c) (control shift ?s)]
     'slime-my-complete-form))
SWANK側
(IN-PACKAGE :SWANK)

(DEFSLIMEFUN MY-COMPLETE-FORM (RAW-FORM)
  (FLET ((STRING-UPCASE-SAFE (X)
           (IF (STRINGP X) (STRING-UPCASE X) X)))
    (MATCH (MAPCAR #'STRING-UPCASE-SAFE RAW-FORM)
      (("MAPCAR" . REST) "(LAMBDA ())")
      (("SET-MACRO-CHARACTER" . REST) 
       "#\\ (LAMBDA (STREAM CHAR) (DECLARE (IGNORE CHAR)))")
      
      (("SET-DISPATCH-MACRO-CHARACTER" . REST)
       "#\\ #\\ (LAMBDA (STREAM SUBCHAR ARG) (DECLARE (IGNORE SUBCHAR ARG)) )")

      (("EVAL-WHEN" (":COMPILE-TOPLEVEL" ":LOAD-TOPLEVEL" ":EXECUTE") . REST) 
       ":?")
      
      (("EVAL-WHEN" . REST) 
       "(:COMPILE-TOPLEVEL :LOAD-TOPLEVEL :EXECUTE)")

      (("LOOP" . REST) 
       ":FOR X :FROM 0 :TO 100 :COLLECT X")

      (("LET" ("" %CURSOR-MARKER%) . REST) 
       "(X X)")
      
      (("LET" . REST) 
       "()")

      (("DEFPACKAGE" . REST)
       ":FOO (:USE :CL)")

      (("REDUCE" #:_ #:_ %cursor-marker%)
       ":INITIAL-VALUE")

      (("REDUCE" #:_ #:_ "" %cursor-marker% . REST)
       ":INITIAL-VALUE")

      (OTHER :NOT-AVAILABLE))))

2010-08-28

REPLでTwitter

| 01:30 | REPLでTwitter - わだばLisperになる を含むブックマーク はてなブックマーク - REPLでTwitter - わだばLisperになる

Index of /project/cl-twitterというCommon LispのTwitterクライアントがあるのですが、この1ヶ月位試しに使ってみています。

自分の使い方なのですが、SLIMEでREPLにタイムラインを表示させっぱなしにして、つぶやき関数をエディタバッファ上で評価でつぶやきという感じにしています。

コンパイルした結果や警告とつぶやきが混ざって表示されたりしてカオスなのですが、SLIMEを立ち上げっぱなしの人には割と便利じゃないかなあと思っていますが、誰得情報なのかも知れませんw

そしてもちろん、プログラミングの集中の邪魔にはなりますw

とりあえず、自分はこんな感じで必要な範囲で適当に関数を定義して使っています。

;; ユーザーオブジェクト(ログイン)
(DEFPARAMETER *G??????* (TWIT:AUTHENTICATE-USER "G??????" "password"))

;; 牧歌的な複数ユーザー対応
(SETQ *TWITTER-USERS* (LIST *G??????*))

(DEFUN PRINT-ALL-TWEETS ()
  (LET ((ANS () ))
    (DOLIST (USER *TWITTER-USERS*)
      (LET ((TWIT:*TWITTER-USER* USER))
        (SETQ ANS
              (NCONC (TWIT:TWITTER-OP :FRIENDS-TIMELINE)
                     ANS))))
    (TWIT:PRINT-TWEETS 
     (SORT (DELETE-DUPLICATES ANS :KEY #'TWIT::TWEET-ID)
           #'<
           :KEY #'TWIT::TWEET-ID))
    NIL))

;; SLIMEのREPLに表示
(DEFPARAMETER *TWITTER-OUTPUT*
  #.*STANDARD-OUTPUT*)

;; 別スレッドで回す
(DEFUN START-TWIT ()
  (PORTABLE-THREADS:SPAWN-THREAD 
   "twit"
   (LAMBDA ()
     (LET ((*STANDARD-OUTPUT* *TWITTER-OUTPUT*))
       (LOOP (PRINT-ALL-TWEETS)
             (SLEEP (* 6 60)))))))

;; 更新用関数
(DEFUN UPDATE-G?????? (MESG)
  (LET ((TWIT:*TWITTER-USER* *G??????*))
    (TWIT:UPDATE MESG)))

色々便利関数を定義したり、結果をブラウザに表示させてみたり、色々工夫してみるとLISPプログラミングを楽しめるかもしれません。

2010-05-12

SLIMEとLTDを使ってCLのコードをDylanに変換して表示する

| 19:06 | SLIMEとLTDを使ってCLのコードをDylanに変換して表示する - わだばLisperになる を含むブックマーク はてなブックマーク - SLIMEとLTDを使ってCLのコードをDylanに変換して表示する - わだばLisperになる

まったくもって誰も興味がなさそうなエントリーですが、LTDとSLIMEを組み合わせてみたら面白いかなと思い、組み合わせて遊んでみました。

LTDは、最近翻訳された「実用Common Lisp」の著者であるPeter Norvig氏が作成したCommon LispをDylanに変換するツールです。

SLIME

(defun random-string (&key (length 10) (set :lower-alpha))
  "Returns a random lower-case string."
  (declare (optimize (speed 3)))
  (let ((s (make-string length)))
    (declare (simple-string s))
    (dotimes (i length s)
      (setf (schar s i) (random-char set)))))

のようなCLのコード上でslime-ltdすると

// LtD

define method random-string (#key length = 10, set = #"lower-alpha")
  // Returns a random lower-case string.
  let s :: <simple-string> = make(<string>, size: length, fill: ' ');
  for (i from 0 below length) s[i] := random-char(set); finally s; end for;
end method random-string;

のように別枠のバッファにDylanに変換され表示されるようにします。

クレジットの箇所を読むと、LTDの元になったScott McKay氏の書いたlisp-to-dylan.lispはエディタのバッファを置き換えるというものだったらしいので、なんとなく逆行してしまっている気しますが、表示されたDylanのコードを眺めるのも面白いので、これはこれで良いかなと思います。

変換されたコードでは、きちんとコメントが反映されていたり、マクロは展開されたりします。

動かすのに必要なもの

  1. slime.el
  2. dylan-mode.el

他、ANSI CLで廃止になった記述等がありコンパイルできない箇所がある(SBCL)ので適当に直します。

  1. LTDはCL-USERパッケージを前提にしているので、ltdというパッケージを利用するように変更。
  2. read.lispのrecord-file-positionsの置かれている位置を利用している関数より先に持ってゆく
  3. loopの中で、by 'cddrというのを、by #'cddrに直す
  4. string-char型は廃止なので、characterに変更

SLIME側のコード
;; LtD 
(eval-after-load "slime"
  '(progn
     (defun slime-ltd (times)
       (interactive "p")
       (slime-eval-and-ltd
        `(swank:eval-and-grab-output
          ,(format "(WITH-INPUT-FROM-STRING (IN (PRIN1-TO-STRING '%s))(LTD::LTD-EXP IN *STANDARD-OUTPUT*))" 
                   (slime-defun-at-point)))))
     
     (defun slime-eval-and-ltd (form)
       (slime-eval-async form (slime-rcurry #'slime-show-ltd
                                            (slime-current-package))))
     
     (defun slime-show-ltd (string package)
       (slime-with-popup-buffer ("*SLIME LtD*" package t t)
         (dylan-mode)
         (princ "// LtD")
         (terpri)
         (terpri)
         (princ (first string))
         (goto-char (point-min))))
     
     ;; SUPER-SHIFT-D
     (define-key slime-mode-map
       [(super shift ?d)] 'slime-ltd)))

2009-03-22

GaucheでSLIME

| 22:43 | GaucheでSLIME - わだばLisperになる を含むブックマーク はてなブックマーク - GaucheでSLIME - わだばLisperになる

gaucheでも、SLIMEが使えたら、もっとGaucheのコード書くようになる気がするなあと常々思っていたのですが、ついに、swank-gaucheが登場しました!

まだ発展途上ということですが、今のところでもシンボルの補完と、マクロ展開ができるのでSLIMEに慣れた方なら便利に使えると思います!

自分的にはArglistが早く実装されてくれると物覚えの悪い自分には嬉しいので、期待して待ちたいです。…いや、自分でもできそうなら作ってみたいです(笑)

lequeさんのgauche-modeと合体するとかなり便利に使えるんじゃないかと想像しているのですが、とりあえず思い付いたユーティリティを書いてみました。

  1. Gaucheのリファレンスを引く
  2. マクロ展開をプリティプリント

の2点です。

プリティプリントには、ppが必要です。

基本的な設定(swank-gauche.scm参照)

;; Emacs Lisp
(pushnew "<path-to-slime-dir>/slime/contrib" load-path :test #'equal)
(require 'slime-scheme)
(setq slime-lisp-implementations
      '((gauche ("gosh") :init gauche-init)))

(defun gauche-init (file encoding)
  (format "%S\n\n"
          `(begin
             (add-load-path "<path-to-slime-dir>/slime/contrib") ;; add load path to swank-gauche.scm
             (require "swank-gauche")
             (import swank-gauche)
             (start-swank ,file))))

(defun gauche ()
  (interactive)
  (slime 'gauche))

(defun find-gauche-package ()
  (interactive)
  (let ((case-fold-search t)
        (regexp (concat "^(select-module\\>[ \t']*"
                        "\\([^)]+\\)[ \t]*)")))
    (save-excursion
     (when (or (re-search-backward regexp nil t)
               (re-search-forward regexp nil t))
       (match-string-no-properties 1)))))

(setq slime-find-buffer-package-function 'find-gauche-package)
(setq slime-complete-symbol-function 'slime-complete-symbol*)

Gaucheのリファレンスを引く(C-c C-d C-sh-h)

;; Emacs Lisp
(progn
  (defun gauche-ref-lookup ()
    (interactive)
    (browse-url
     (format "http://practical-scheme.net/gauche/man/?l=jp&p=%s" (thing-at-point 'symbol))))
  
  (define-key slime-mode-map [(control ?c) (control ?d) (shift ?h)] 'gauche-ref-lookup))

マクロ展開をプリティプリント

;; swank-gauche.scm
(use util.match)
(use pp)

(define (subst-by subst pred lst)
  (define self (cut subst-by subst pred <>))
  (match lst
    (() ())
    (((? pred head) . tail)
     (cons (subst head) (self tail)))
    (((? pair? head) . tail)
     (cons (self head) (self tail)))
    ((head . tail)
     (cons head (self tail)))))

(defslimefun swank-macroexpand-1 (string)
  (let ((sexp (read-from-string string)))
    (if (eof-object? sexp)
        ""
        (with-output-to-string 
          (lambda ()
            (pretty-print 
             (subst-by identifier->symbol identifier?
                       (macroexpand-1 sexp))))))))

(defslimefun swank-macroexpand-all (string)
  (let ((sexp (read-from-string string)))
    (if (eof-object? sexp)
        ""
        (with-output-to-string 
          (lambda ()
            (pretty-print 
             (subst-by identifier->symbol identifier?
                       (macroexpand-1 sexp))))))))
  • 動作具合(slime-macroexpand-1)
(match lst
    (() ())
    (((? pred head) . tail)
     (cons (subst head) (self tail)))
    (((? pair? head) . tail)
     (cons (self head) (self tail)))
    ((head . tail)
     (cons head (self tail))))

;==>
(if
 (null? lst)
 ((lambda () ()))
 (if
  (pair? lst)
  (if
   (pred (car lst))
   ((lambda (head tail) (cons (subst head) (self tail))) (car lst) (cdr lst))
   (if
    (pair? (car lst))
    ((lambda (head tail) (cons (self head) (self tail))) (car lst) (cdr lst))
    ((lambda (head tail) (cons head (self tail))) (car lst) (cdr lst))))
  (match:error lst)))

2009-01-15

TIMEもめんどくさい

| 05:39 | TIMEもめんどくさい - わだばLisperになる を含むブックマーク はてなブックマーク - TIMEもめんどくさい - わだばLisperになる

以前に、毎度DESCRIBEを書くのが面倒ということでelispを書いてみましたが、TIMEも面倒なので同じように書いてみました。

どうも最近、SLIMEslime-with-popup-bufferに変更があったみたいでフォーカスの制御を明示的にするようになったようなので前のDESCRIBEのものも修正してみました。

(fib 30)

の上でC-sh-tすると

(fib 30)

;=> 832040
----------
Timing the evaluation of (FIB 30)

User time    =        0.060
System time  =        0.000
Elapsed time =        0.063
Allocation   = 0 bytes
0 Page faults

みたいな窓が出て、qで終了。

;; Emacs lisp
(progn
  ;; time
  (defun slime-time-form ()
    (interactive)
    (let ((defun-at-point (slime-defun-at-point)))
      (slime-eval-and-time
       defun-at-point
       `(swank:eval-and-grab-output
         ,(format "(let ((*trace-output* *standard-output*))(time %s))" defun-at-point)))))
  
  (defun slime-eval-and-time (orig-form form)
    (slime-eval-async form (slime-rcurry #'slime-show-time
                                         (slime-current-package)
                                         orig-form)))
  
  (defun slime-show-time (string package orig-form)
    (slime-with-popup-buffer ("*SLIME Time*" package t t)
      (lisp-mode)
      (princ orig-form)
      (princ "\n;=> ")
      (princ (second string))
      (princ "\n----------\n")
      (princ (first string))
      (goto-char (point-min))))
  
  ;; control-shift-t
  (define-key slime-mode-map
    [(control shift ?t)] 'slime-time-form))
;; Emacs lisp
(progn
  ;; describe
  (defun slime-describe-form ()
    "(Describe) the form at point."
    (interactive)
    (slime-eval-and-describe
     `(swank:eval-and-grab-output
       ,(format "(describe %s)" (slime-defun-at-point)))))

  (defun slime-eval-and-describe (form)
    "Describe FORM in Lisp and display the result in a new buffer."
    (slime-eval-async form (slime-rcurry #'slime-show-describe
                                         (slime-current-package))))

  (defun slime-show-describe (string package)
    (slime-with-popup-buffer ("*SLIME Describe*" package t t)
      (lisp-mode)
      (princ (first string))
      (goto-char (point-min))))

  ;; control-shift-d
  (define-key slime-mode-map
    [(control shift ?d)] 'slime-describe-form))

2009-01-01

describeが面倒臭い

| 21:57 | describeが面倒臭い - わだばLisperになる を含むブックマーク はてなブックマーク - describeが面倒臭い - わだばLisperになる

最近インスタンスの中身を確認したいことが多いのですが、describeの結果を確認するためにd.e.s.c.r.i.b.eといちいちタイプするのが面倒なのでslimeの中の関数を参考にしてelispを書いてみました。

;; EMACS Lisp
(progn
  (defun slime-describe-form ()
    "(Describe) the form at point."
    (interactive)
    (slime-eval-and-describe
     `(swank:eval-and-grab-output
       ,(format "(describe %s)" (slime-defun-at-point)))))

  (defun slime-eval-and-describe (form)
    "Describe FORM in Lisp and display the result in a new buffer."
    (slime-eval-async form (slime-rcurry #'slime-show-describe
                                         (slime-current-package))))

  (defun slime-show-describe (string package)
    (slime-with-popup-buffer ("*SLIME Describe*" package)
      (princ string)
      (goto-char (point-min))))

  ;; control-shift-d
  (define-key slime-mode-map
    [(control shift ?d)] 'slime-describe-form))

使い方

(make-instance 'mime:text-mime :content "あけましておめでとう")

等のトップレベルのフォームの上で実行すると

(#<CL-MIME:TEXT-MIME {100C4FE321}>
is an instance of class #<STANDARD-CLASS CL-MIME:TEXT-MIME>.
The following slots have :INSTANCE allocation:
 CONTENT-TYPE                   "text"
 CONTENT-SUBTYPE                "plain"
 CONTENT-TYPE-PARAMETERS        NIL
 CONTENT-ID                     NIL
 CONTENT-DESCRIPTION            NIL
 CONTENT-TRANSFER-ENCODING      :7BIT
 CONTENT-ENCODING               :7BIT
 CONTENT-DISPOSITION            NIL
 CONTENT-DISPOSITION-PARAMETERS   NIL
 CONTENT                        "あけましておめでとう"
 MIME-VERSION                   "1.0"
 CHARSET                        "us-ascii"
 )

のような画面が別枠で開き、qで閉じます。

既に存在しているような気がしてならないのですが、slime-describe-symbolはあっても(describe ...)の結果を表示するものは探してもみつけられませんでした。

ということで作ってみたのですが、SLIMEでdescribeをフォームにかける方法をご存知の方は教えて下さい!

2008-10-31

SLIMEとElispを連携させたい その2

| 16:35 | SLIMEとElispを連携させたい その2 - わだばLisperになる を含むブックマーク はてなブックマーク - SLIMEとElispを連携させたい その2 - わだばLisperになる

コメント覧にて、佐野さんから値を取得する場合には、slime-evalを使う、と教えてもらったので早速試してみました。

slime-evalの仕様がいまいち分かっておらず、シンボルのパッケージの指定は強制的に文字列で置換した後にSLIMEに送ることにしてみました。

;; Emacs Lisp
(require 'cl)

(defun has-package-name-p (symbol)
  (and (position ?: (symbol-name symbol)) 'T))

(defun put-package-name (tree &optional pkg)
  (let ((pkg (symbol-name (or pkg 'cl-user))))
    (*put-package-name tree pkg)))

(defun *put-package-name (tree pkg)
  (cond ((null tree) () )
        ((consp (car tree))
         (cons (*put-package-name (car tree) pkg)
               (*put-package-name (cdr tree) pkg)))
        ((and (symbolp (car tree))
              (not (has-package-name-p (car tree))))
         (cons (intern (concat pkg "::" (symbol-name (car tree))))
               (*put-package-name (cdr tree) pkg)))
        ('T (cons (car tree)
                  (*put-package-name (cdr tree) pkg)))))

(defmacro cl-funcall (fn &rest expr)
  `(slime-eval 
    ',(put-package-name `(funcall ,fn ,@expr))))

;; 動作
(+ (cl-funcall #'+ 30 40) 30)
100

(cl-funcall #'ppcre:scan "良し" "これで良し")
3

効率は悪そうですが、まずこれで良しとします。cl-evalとかも欲しいかも。

SLIMEとElispを連携させたい

| 13:41 | SLIMEとElispを連携させたい - わだばLisperになる を含むブックマーク はてなブックマーク - SLIMEとElispを連携させたい - わだばLisperになる

先日はSLIME経由で、CLの関数を呼んでみたりしました(→LINK)

しかし、これだけだとつまらないので、もう一歩進んで、CLの関数をELispと混ぜて使えたら便利だなということで、適当に試してみました。

希望としては、Elisp上で

(+ 33 (cl-funcall #'fib 10))
;=> 88

みたいな事ができれば最高です。

とりあえずElisp上でCLの関数が定義できるようにしてみました。

先日定義した、slime-eval-mesgを使用します。

(defmacro define-cl-function (name arg &rest body)
  (slime-eval-mesg
   (format "(defun %s %s %s)"
           name arg (mapconcat (lambda (x) (format "%s" x)) body " "))))

(defun eval-cl (expr)
  (slime-eval-mesg (format "%s" expr)))

;; 関数を定義してみる
(define-cl-function fib (n)
  (if (< n 2)
      n
      (+ (fib (1- n))
         (fib (- n 2)))))

(eval-cl '(fib 20))
;>>> 6765

とりあえずですが、関数は定義できました。ちなみにパッケージの連携については謎です。

それで、その値を取得したい訳なのですが、

(defun cl-funcall (fn &rest args)
  (slime-eval-async
   `(swank:eval-and-grab-output 
     ,(format "(funcall #'%s %s)" 
              fn (mapconcat (lambda (x) (format "%S" x)) args " ")))
   (lambda (result)
     (setq *ans* (cadr result))))
  *ans*) ;; 大域変数に逃すという苦肉の策。しかし*ans*の値がリアルタイムに取得できない。

みたいなものを定義しても、どうやら駄目なようです。

SLIMEの値の受渡しについてもう少し探ってみる必要があるようですが、自分は、根性無しなので知っている方がいらっしゃったら是非教えて欲しいです(笑)

2008-10-27

EMACSからSLIMEにS式を投げてEMACS側で受けとりたい

| 05:28 | EMACSからSLIMEにS式を投げてEMACS側で受けとりたい - わだばLisperになる を含むブックマーク はてなブックマーク - EMACSからSLIMEにS式を投げてEMACS側で受けとりたい - わだばLisperになる

自分は、はてな日記をsimple-hatena-modeで書いて、SLIMEで投稿ということを試みているのですが、EMACS->SLIMEという風にSLIMEに式を送ることは比較的簡単なのですが、SLIMEから結果を受けとる方法は良く分からないので放置していて、面倒なのでREPLから投稿したりしていました。(とはいえSLIMEのREPLには履歴機能があるのでそんなに不便でなかったりします)

しかし、SLIMEは、EMACSとCL処理系の連携をしているわけであり、結果を受け取れない筈はありません。

という訳でちょっとslime.elを追っ掛けてみたら、すぐ目的の関数はみつかってしまいました。

目的の関数は、slime-eval-printという関数で、式を文字列として受けとって、結果をS式で返してくれる関数のようです。

これをちょっと改造すれば色々応用できそうだということで、結果をエコーエリアに表示してくれるようなものを作成しました。

(defun slime-eval-mesg (string)
  "Eval STRING in Lisp; Echo any output."
  (slime-eval-async `(swank:eval-and-grab-output ,string)
                    (lambda (result)
                      (destructuring-bind (output value) result
                        (message (format "%s" value))))))

この関数の動作の詳細は良く分かっていないので、本当に適当です。(outputは、出力、valueは返り値の様子)

それで、simple-hatena-modeの日記を投稿する関数/simple-hatena-submitを上書きして内容をCLのはてな日記を投稿する関数を呼び出すようにします。

(defun simple-hatena-submit ()
  (interactive)
  (slime-eval-mesg "(post-todays-group-entry)"))

CL側のpost-todays-group-entryは、日記を投稿して成功したら文字数を返すような関数で、成功すれば、エコーエリアに文字数が表示されることになります。

ということで、早速このエントリもこの仕組みで投稿していますが、今のところは上手く行っているようです。(エラー時のリカバリはどうするのかという謎は残っていますが…)

2008-09-22

ClojureでSLIME その2

| 19:54 | ClojureでSLIME その2 - わだばLisperになる を含むブックマーク はてなブックマーク - ClojureでSLIME その2 - わだばLisperになる

自分は、SLIMEはEMACS内からSWANKを起動するのではなく、SWANKは別に起動して、slime-connectで接続して使っています。

配布のままのswank-clojureだと、EMACS内で起動するようになっているので、slime-connectで接続できるよう、別にSWANKを起動するような起動スクリプトを書いてみました。

Clojure側で準備して、シェルスクリプトで起動させます。

$ swank-clojure
Swank port =>  9696
Clojure
...
#!/bin/sh
#
# swank-clojure

CLOJURE_HOME=~/Desktop/Clojure

cd $CLOJURE_HOME
#java -cp clojure.jar clojure.lang.Repl
java -jar $CLOJURE_HOME/clojure.jar $CLOJURE_HOME/swankd.clj
SWANKサーバ起動
;;;;
;;;; SWANKD
;;;;
;;;; swankd.clj

;; swank-clojureの場所をfile...に指定します。
(clojure/add-classpath "file:////u/mc/Desktop/Clojure/jochu-swank/")
(clojure/require 'swank)

;; いらない?
(swank/ignore-protocol-version "2008-09-14")

(in-ns 'swank)
(defn swankd [port]
  (setup-server port 
                (fn [x] (println "Swank port => " port))
                connection-serve))
  
;; start!
(in-ns 'user)
;; ポートは好きな空いてるとこを…
(swank/swankd 9696)

2008-09-21

ClojureでSLIME

| 20:32 | ClojureでSLIME - わだばLisperになる を含むブックマーク はてなブックマーク - ClojureでSLIME - わだばLisperになる

開発環境の設定は、Clojureのチュートリアルにも書いてあり、なんとClojure用のSLIMEまであります(*'-')

しかし、どうも更新が激しいらしく、どれを参照して良いものやら、という感じで、実際、上のチュートリアルの通りにしても動かないので今日現在で動く設定を晒してみることにしました。

恐らく、SLIMEもCVS版推奨という感じなのではないかと思います。

run-clojureというコマンドが定義してあるので、これでSLIMEが起動します。

SLIMEの具合ですが、引数の表示、マクロ展開、関数名補完、インスペクタ、ドキュンメントストリングの参照(C-c C-d d)を初めとして普段使いそうな機能は大体動きます。

ということで、CLは嫌いだけど、SLIMEは体験してみたいという向きにもお勧めかもしれません。

#!/bin/sh

#Clojureの置き場所
CLOJURE_HOME=~/Desktop/Clojure

cd $CLOJURE_HOME
java -jar $CLOJURE_HOME/clojure.jar $*
;;;;
;;;; Clojure mode
;;;;
;;;; (require 'cl)してないと動かないw

;; clojure-modeの置き場所
(pushnew "p/a/t/h" load-path)
(require 'clojure-mode)
 
;;;;
;;;; Setup slime
;;;;
;;;;(pushnew "c:/dev/cvstree/slime.cvs" load-path)
;;;; slimeは既に他で設定してある。
 
(setf slime-lisp-implementations
      ;; clojure-initじゃなくて、swank-clojure-initに変更になっていた。
      '((clojure ("~/bin/clojure") :init swank-clojure-init) 
                ))

(require 'slime-autoloads)
;; slime-scratch有効にしてるけど、上手く動かない…。
(slime-setup '(slime-scratch slime-editing-commands))

;; clojure-swankの場所
(pushnew  "/p/a/t/h" load-path)
(require 'swank-clojure)
 
(defun run-clojure ()
  "Starts clojure in slime"
  (interactive)
  (slime 'clojure))

2008-04-27

SLIME勉強会@新宿 4/26 (土) 13:00〜20:00 (5)

| 23:28 | SLIME勉強会@新宿 4/26 (土) 13:00〜20:00 (5) - わだばLisperになる を含むブックマーク はてなブックマーク - SLIME勉強会@新宿 4/26 (土) 13:00〜20:00 (5) - わだばLisperになる

雑談篇

(1)〜(4)のような感じで、SLIMEを俯瞰してみていました。

改めて確認してみると、使っていなかった便利機能が結構ありました。

自分は、slime-selectorは全然使っていなかったのですが、使ってみたところ結構便利なので、積極的に使っていこうという感じです。

また、SLIMEとanything.elを組み合わせたりすれば、もっと便利に使えるようになりそうです。(私はanything.elを活用できていないので実際にできるのかどうか良く分かっていませんが(笑))

本編は、3時間位だったと思うのですが、そこから4時間位雑談が続きました!

以下、雑談で出たネタを纏めてみたいと思います。

実際に勉強会として集合するのは、割とエネルギーが必要、IRCで勉強会というのはどうだろう。

→まあまあ良いのでは?

日本で、IRCのLISP部屋として盛り上がっているのはどこか

→どこにもないのでは?

海外のfreenode.netの#lispは過去ログが閲覧できるプログラムが動いていて、また、HyperSpecが呼べたりlisppateというペーストしたコードを綺麗に表示してくれるサイトと連携できるようになっていて、非常に便利そう。

lisppateの機能自体は、CLのプログラムとして配布されている。

そのなかの、colorize.lispはコードをハイライト表示でHTMLにしてくれるプログラムで便利に使えそう。

lisppasteは、asdf-install可能。…でも依存パッケージがリンク切れ…。

組み込み用途などでLISPの便利さを生かせないか

ECL等、Cのコードを生成してくれる処理系を使ってみたが、なかなか思ったようなのがない。

GOOは、インラインでCのコードを書けたり、作者が組み込みに興味があるようなので、Cや組み込み分野との親和性は高そう。

http://people.csail.mit.edu/jrb/goo/

http://people.csail.mit.edu/jrb/Projects/alien-goo-intro.html

http://people.csail.mit.edu/jrb/Projects/alien-goo-talk.pdf

vcgoo154a.zipなどもあるので、Windowsでも行けるかも

ちょっと違うけれど、CをS式風に書けるのもある。

http://www.cliki.net/scexp

コードが消失していて、

http://jsnell.iki.fi/tmp/scexp-0.9.tar.gz

に置いてあるのが見付かるだけ…。

リストの破壊的操作について。ポインタ操作系。
(defun nrev (lst)
  (do ((1st (cdr lst) (if (endp 1st) 1st (cdr 1st)))
       (2nd lst 1st)
       (3rd () 2nd))
      ((atom 2nd) 3rd)
    (rplacd 2nd 3rd)))

(let ((foo '(1 2 3 4)))
  (nrev foo))
;=> (4 3 2 1)

等々、rplacaや、rplacdを駆使した分かりづらいコード。

去年ちょっとしたOn Lispブームのようなものがあった気がするが、何でなんだろうか。

On LispはCLのマクロがテーマという非常に特殊な本だと思うんだけれど…。

→やっぱり、Paul Grahamがカリスマということなのでは?

xyzzyで、defpackageでexportを指定しても、exportしてくれないのはどういう理由?

→バグな様子。

CLには、edというエディタを呼び出す関数が標準で装備されている

→edは、Lispマシンでは、Zmacsを呼び出すものだった。

→4.x BSDがメインターゲットだったFranz Lispでは、viという関数があり、viを呼び出すようになっていた。

BSDだし勿論メジャーなエディタはEMACSではなくvi。

(調べたら、exもありました。vilや、exlもあって、これは編集後ロードするというもの)

viも昔は、LISP編集に便利な機能が沢山あったらしい(あった筈)

等々他にも沢山ネタがあったと思うのですが、メモ取ってなかったので忘れてしまいました…。

まとめ

自分の突発的な見切り発車で色々ご迷惑をお掛けすることがあったと思うのですが、お付き合い頂いて本当にありがとうございました!

次回、勉強会ですが、実際に現地に集合するのは、会場の確保等、なかなか難しいところがあるので、IRCで開催してみるのはどうかチャレンジしてみたいと思います!

SLIME勉強会@新宿 4/26 (土) 13:00〜20:00 (3)

| 21:51 | SLIME勉強会@新宿 4/26 (土) 13:00〜20:00 (3) - わだばLisperになる を含むブックマーク はてなブックマーク - SLIME勉強会@新宿 4/26 (土) 13:00〜20:00 (3) - わだばLisperになる

CVS版 slime/contrib以下のファイルを点検してみよう

contrib以下のファイルは、どうやら(slime-setup '(...))で読みこむらしい

bridge.el

詳細不明

inferior-slime.el

inferior-lispのようなものか?

slime-asdf.el

slime-load-systemの定義らしい。

slime-autodoc.el

エコーバッファに引数情報を表示してくれる機能

読み込むと少しと反応が変わる程度かも。

slime-banner.el

起動時の最初のアニメーションとか。

slime-c-p-c.el

in-pa→in-package形式の補完が可能になる

slime-editing-commands.el

便利なものがおおいので中身を把握しておくのが吉かも。

slime-fancy.el

このファイルで便利機能をまとめてロードできるらしい

slime-fuzzy.el

曖昧方式の補完C-c C-iの方

slime-highlight-edits.el

編集したところが色付きになり、コンパイルが通るまで目立つ状態になる。

若干好き嫌いは分かれるかも

slime-indentation.el

インデントの設定を纏めたもの。

ifのインデント等は、デフォルトでは癖がある。

slime-presentation-streams.el、slime-presentations.el

追記(tszさんからのツッコミコメント)

2008/04/28 00:39
slime-presentationですが、ハッシュテーブルなどの
表示不可能オブジェクトをreplにコピーアンドペーストする
あの機能のことの様です。
さらに、replに表示された#<>記法のオブジェクトを
右クリックして調べたり出来るみたいです。

なるほど! 読み込み不可オブジェクトをREPLで評価するためには、これを読み込む必要があったんですね!

プレゼン用なのだろうか、謎。

slime-references.el

sbcl専用マニュアル。SBCLの場合は、読み込んでおくと吉かも。

デバッガに入ったときに、

See also:

SBCL Manual, Package Locks [:node]

Common Lisp Hyperspec, 11.1.2.1.2 [:section]

のような表示になり、クリックするとSBCLの該当マニュアルページに飛べる。

slime-tramp.el

ssh接続で使う際のユーティリティ。クライアントとサーバでのパス名の変換など。

slime-typeout-frame.el

主にエコーバッファを別窓で表示させるためのもの。

slime-xref-browser.el

クロスリファレンスを表示してくれる、らしい。

swank-goo.goo

gooのswankサーバ

swank-kawa.scm

kawaでもswankできるらしい。

swank-mit-scheme.scm

1. You need MIT Scheme (version 7.7.0 and 7.7.90 seem to work).

ということで、MIT Schemeでも使えるらしい。

meter.lisp

なぜここにあるのか不明。

SLIME勉強会@新宿 4/26 (土) 13:00〜20:00 (2)

| 03:32 | SLIME勉強会@新宿 4/26 (土) 13:00〜20:00 (2) - わだばLisperになる を含むブックマーク はてなブックマーク - SLIME勉強会@新宿 4/26 (土) 13:00〜20:00 (2) - わだばLisperになる

SLIMEを使う

便利機能紹介

ここで紹介している機能のEMACSでの基本キーバインドに関しては、tszさんが分かりやすい一覧表で纏められていますので、そちらも参照して下さい!

式の評価

slime-pprint-eval-last-expression

C-c C-p便利。これを基本に使っても良いかも。

C-c C-cでコンパイル。

コンパイルしてエラーの個所を表示してくれる。

エラーになっている個所が色付きのアンダーラインで表示される。

M-n、M-pでソースファイルの該当個所場所に飛べるので便利!

マクロ展開

非常に便利なので、本当にお勧め。これの支援が無いとマクロが書けなくなる位、便利。

SLIME上では(macroexpand ...)と書く必要はないのだ!

  • 全部展開する

C-c M-m

関数定義のソースコードに飛ぶ

M-.でソースへ

M-,でもどる

という風にどんどん進める

処理系が対応している必要あり (SBCL、Clozure等は対応している)

関数名補完

c-p-c、Fuzzy(C-c M-i)方式等いろいろある。

c-p-cは、m-v-bi→multiple-value-bindと補完。ハイフンを入力する必要あり。

Fuzzyはなんとなくの感じから展開mvbind(C-c M-i)→multiple-value-bind等々

REPLの履歴

Bashのように履歴が辿れる。

REPL上で、M-n、M-p。M-rもある。Eshellっぽいキーバインド。

読み込み不可オブジェクトをREPLで読み込める

読み込めない筈の#<foo>等もよみこめる。主に対話操作で便利。

SLIME Fancyが読み込まれている必要ありかも。

複数の処理系を切り換えて使える。

C- - M-x slimeで切り換えられる。(slime-connectでない場合)

複数の処理系を同時起動可能。しかし、編集しているLISPファイルをどの処理系が担当しているのか把握できなくなることが多いので、あまりお勧めできないかも。

パッケージの移動とソースファイルとのシンクロ

C-c ~でソースファイルとソースファイルが指定しているパッケージを同期できる。

←割とファイルを開いた段階で自動で内容をみて判別してくれるのでは?(tsz)

←そういえば、そうかもしれませんね(笑) どういう時に使うんだろう…。自分は割と手癖で打ち込んでます(g000001)

ファイルのロード、コンパイル

C-c C-lでファイルのロードC-c C-kで、コンパイルしてからロード

ASDFのロード load-systems

asdf-installはないが、 (asdf:oos ~)はSLIMEから可能。

M-x slime-load-system

と打ち込んで、パッケージを選択。パッケージ名は補完が効く。

SLIME上で(asdf:oos ...)と打つ必要はないのだ!。

HyperSpecとの連携

非常に便利で、必須な機能。(C-c C-d h)

憶えるのが厄介な、FORMATの指示子を引くこともできる! (C-c C-d ~)

Cltl2も引きたい→ILISPにcltl2.elがあるんで、引き抜いてきてロードすれば使えます。

(eval-after-load "cltl2"
  (progn 
    (require 'cltl2)
    ;; SLIMEっぽく、slime-cltl2-lookupという名前のエイリアスを作成
    (defalias 'slime-cltl2-lookup 'cltl2-lookup)
    ;;ドキュメントの場所
    (setq cltl2-root-url "http://foo.local/docs/cltl/")))
バッファ間の移動など(slime-selector活用)

M-x slime-selectorでSLIMEを操作する上で便利なslime-selectorが起動。

割と頻繁うので、

(global-set-key [(control ?\;)] 'slime-selector)

等に便利な場所に割り当てると良いかも。

slime-selectorで切り換えられるもの

キー名前説明
?Selector help buffer.ヘルプ
cSLIME connections buffer.接続状況が確認できる。接続表示の上でkを押すことにより切断可能
d*sldb* buffer for the current connection.*sbdb*のバッファ
emost recently visited emacs-lisp-mode buffer.直近のelispバッファへ移動
iinferior-lisp* buffer.*inferior-lisp* bufferへ移動
lmost recently visited lisp-mode buffer.直近のlispバッファへ移動
rSLIME Read-Eval-Print-Loop.REPLへ移動
s *slime-scratch* buffer.emacsや、xyzzyの*scratch*のような感じで、式をC-jすると後に結果の文字が挿入されるのバッファ。*scratch*が好きな人にはおすすめ。
tSLIME threads buffer.スレッド別に表示される。選択してC-kを押すことでスレッドを終了できる。
v *slime-events* buffer.クライアントとサーバの通信の様子がみれる
インスペクタ

(C-c I)でオブジェクトをいろいろ調べられる

パッケージの場合、内容を確認できるのが便利。エクスポートされている関数一覧など見れる。

SLIME Fancyが読み込まれていないと、綺麗に表示されない?

デバッガ

tで詳細表示にトグル

M-n、M-pでソースと対応づけられながら進めることが可能。

内部で式の評価をすることも可能。

クロスリファレンス

(C-c >)、(C-c <)呼んでいる関数、呼ばれている関数を調べる。一覧も表示される。

プロファイリング

slime-toggle-profile-fdefinition

TRACEのように任意の関数を指定してプロファイリング。

結果表示で結果表示。呼ばれた回数等が表示される。

全部のプロファイリングを中止。

  • slime-profiled-functions

プロファイリング中の関数の一覧を表示

全部のコッカを閉じる(過不足なく)

slime-close-all-parens-in-sexp(C-c C-])

式をコメントアウト/復帰 slime-balanced-comment

slime-insert-balanced-commentsでコメントアウト

(do ((i 0 (1+ i)))
    ((= 10 i) (p__rint "foo?")))

;; コメントアウトしたい式の先頭で、slime-insert-balanced-comments
;; →
(do ((i 0 (1+ i)))
    ((= 10 i) #|(print "foo?")|#))

;; slime-remove-balanced-commentsで復帰
;; →
(do ((i 0 (1+ i)))
    ((= 10 i) (p__rint "foo?")))
;; 楽ちんだ!

slime-remove-balanced-commentsで復帰

(define-key slime-mode-map [(control ?c) ?\;] 'slime-insert-balanced-comments)
(define-key slime-mode-map [(control ?c) (meta ?\;)] 'slime-remove-balanced-comments)

等々を.emacsへ…。

引数の補完、便利なのか微妙

C-c C-sでずらっと補完。(map __ ) → (map result-type function first-sequence more-sequences...)

ディスアセンブル

(C-c M-d)

SLIME上では(disassemble ...)と書く必要はないのだ!

トレース

(C-c C-t)で指定した関数をTRACEしたりしてくれる。SLIME上では(trace ...)と書く必要はないのだ!

関数定義の取り消し

(C-c C-u) slime-undefine-function

SLIME上では(fmakunbound ...)と書く必要はないのだ!。まあ、そこまで便利でもないけど(笑)

参考資料等

SLIMEでどういうことができるかを解説した良いムービーがある。

Marco Baringer氏がSLIMEの一通りの使い方を解説してくれる、1時間程度のムービー。

まずは、これを一回観るのが手っ取り早い?

SLIME勉強会@新宿 4/26 (土) 13:00〜20:00 (1)

| 01:37 | SLIME勉強会@新宿 4/26 (土) 13:00〜20:00 (1) - わだばLisperになる を含むブックマーク はてなブックマーク - SLIME勉強会@新宿 4/26 (土) 13:00〜20:00 (1) - わだばLisperになる

SLIMEとは

仕組み

処理系がSWANKというサーバを起動しクライアントと通信しながら開発する仕組み

EMACSが主なクライアントとして開発が進められている。

EMACS以外にもクライアントはあり、CUSP等Eclipseで動くものがある。

SWANKにはCL以外にも色々あるようで、確認できている処理系としては、CL、MIT Scheme、Scheme48、Kawa、GOO、Dylan等がある模様。

とりあえず今回は、CLの勉強会なので、CLが対象ということで進めます。

SLIMEで日本語が上手く扱えるかの問題

日本語対応はとりあえずUTF-8が無難?

UTF-8で手軽に使えるもの
  • SBCL
  • Clozure CL
  • Allegro CL
  • CLISP
駄目っぽいもの (基本的に処理系が対応していない)
  • ECL
  • CMUCL
  • ABCL
  • LispWorks(処理系自体は、UTF-8は普通に扱える。SLIMEの説明では簡単に対応できると思う、書いてはいるが、まだ未対応っぽい…。)
未確認
  • MCL

使用形態

(1)SWANKサーバを立てて、クライアントと通信する方法

メリット:

サーバは別に起動させるので、起動が速いという印象がある。(g000001)

←別にどっちの方法でもあまり変わらないのでは?(NANRI)

←そう言われれば、そうかも(g000001)

デメリット:

別にする手間が面倒臭い。

(2)EMACSで起動する時にSWANKサーバとSLIMEのクライアントを起動してしまう方法

複数の処理系を切り換えて使う場合割と切り換えがスムース(な気がする)(g000001)

SWANKを別に起動する方法の場合の設定例

別に起動する場合は、CL側で、SWANKを起動する必要がある。

処理系に初期化ファイル等を渡して起動させる方法がメジャーな様子

/usr/local/sbcl/bin/sbcl --core /var/lisp/sbcl-1.0.16-x86_64-linux.core --load ~/etc/slime.lisp

等々

文字コードをちゃんとクライアントと合わせないと接続が切れる原因になるので注意。

slime.lispの例
;;~/etc/slime.lisp
;;   (swank:create-swank-server PORT) => ACTUAL-PORT
;;   で待機開始。

;; 文字コード設定等
#+sbcl (setq sb-impl::*default-external-format* :utf-8)
#+lispworks (setq STREAM::*DEFAULT-EXTERNAL-FORMAT* '(:utf-8 :eol-style :lf))
(setq swank::*coding-system* 
      #-(or cmu ecl abcl) "utf-8-unix"
      #+(or cmu ecl abcl) "iso-latin-1-unix")

#+cmu (setf swank:*communication-style* nil)

;; swank起動
(swank:create-server :port 
                     #+sbcl  4005
                     #+clisp 4006
                     #+cmu 4007
                     #+ecl 4008
                     #+allegro 4009
                     #+lispworks 4010
                     #+openmcl 4011
                     #+abcl 4012
                     :dont-close t)