scheme-users.jp

Planet Scheme Japan

[Common Lisp][KMRCL]KMRCLを眺める ESCAPE-XML-STRING (109)

今回はKMRCLのstrings.lispから、ESCAPE-XML-STRINGです。

動作は、名前からなんとなく想像できますが、

(KL:ESCAPE-XML-STRING "(< x y)")
⇒ "(&lt; x y)"

という感じです。

定義は、

(defun escape-xml-string (string)
  "Escape invalid XML characters"
  (substitute-chars-strings string '((#\& . "&amp;") (#\< . "&lt;"))))

となっています。

SUBSTITUTE-CHARS-STRINGSの使い道がいまいち分かりませんでしたが、ESCAPE-XML-STRINGのようなことをする場合は確かにうまくはまるなと思いました。

[Common Lisp][KMRCL]KMRCLを眺める SUBSTITUTE-CHARS-STRINGS (108)

今回はKMRCLのstrings.lispから、SUBSTITUTE-CHARS-STRINGSです。

動作は、

(KL:SUBSTITUTE-CHARS-STRINGS "1234567890" '((#\0 . "00")
                                            (#\1 . "11")
                                            (#\2 . "22")
                                            (#\3 . "33")
                                            (#\4 . "44")
                                            (#\5 . "55")
                                            (#\6 . "66")
                                            (#\7 . "77")
                                            (#\8 . "88")
                                            (#\9 . "99")))
⇒ "11223344556677889900"

となっていて、特定の文字を何らかの文字列に置き換えるもののようです。

定義は、

(defun substitute-chars-strings (str repl-alist)
  "Replace all instances of a chars with a string. repl-alist is an assoc
list of characters and replacement strings."
  (declare (simple-string str)
           (optimize (speed 3) (safety 0) (space 0)))
  (do* ((orig-len (length str))
        (new-string (make-string (replaced-string-length str repl-alist)))
        (spos 0 (1+ spos))
        (dpos 0))
      ((>= spos orig-len)
       new-string)
    (declare (fixnum spos dpos) (simple-string new-string))
    (let* ((c (char str spos))
           (match (assoc c repl-alist :test #'char=)))
      (declare (character c))
      (if match
          (let* ((subst (cdr match))
                 (len (length subst)))
            (declare (fixnum len)
                     (simple-string subst))
            (dotimes (j len)
              (declare (fixnum j))
              (setf (char new-string dpos) (char subst j))
              (incf dpos)))
        (progn
          (setf (char new-string dpos) c)
          (incf dpos))))))

となっているのですが、前回眺めたREPLACED-STRING-LENGTHを利用しています。

前回のREPLACED-STRING-LENGTHはいまいち用途が不明でしたが、このSUBSTITUTE-CHARS-STRINGSの補助関数だったようです。なるほど。

しかし、REPLACED-STRING-LENGTHに括り出している処理と同じような処理が、このSUBSTITUTE-CHARS-STRINGSにも含まれていて、なんとなく微妙です。

[Common Lisp][KMRCL]KMRCLを眺める REPLACED-STRING-LENGTH (107)

今回はKMRCLのstrings.lispから、REPLACED-STRING-LENGTHです。

動作は、

(KL::REPLACED-STRING-LENGTH "1234567890" '((#\0 . "00")
                                           (#\1 . "11")
                                           (#\2 . "22")
                                           (#\3 . "33")
                                           (#\4 . "44")
                                           (#\5 . "55")
                                           (#\6 . "66")
                                           (#\7 . "77")
                                           (#\8 . "88")
                                           (#\9 . "99")))
;; (LENGTH "11223344556677889900")
⇒ 20

となっていて、なかなか使いどころが思い浮かびませんが、単一の文字を文字列に置き換えた場合の長さを求めるもののようです。

外部にEXPORTはされていません。

定義は、

(defun replaced-string-length (str repl-alist)
  (declare (simple-string str)
           (optimize (speed 3) (safety 0) (space 0)))
    (do* ((i 0 (1+ i))
          (orig-len (length str))
          (new-len orig-len))
         ((= i orig-len) new-len)
      (declare (fixnum i orig-len new-len))
      (let* ((c (char str i))
             (match (assoc c repl-alist :test #'char=)))
        (declare (character c))
        (when match
          (incf new-len (1- (length
                             (the simple-string (cdr match)))))))))

となっていて、単純に文字列を走査してゆき該当の文字と文字列の対応が与えたALIST中にあれば文字列の長さ分を加えるというもののようです。

[Common Lisp][KMRCL]KMRCLを眺める STRING-TRIM-WHITESPACE (106)

今回はKMRCLのstrings.lispから、STRING-TRIM-WHITESPACEです。

前回、前々回に引き続きで、今回は、行頭と行末の空白文字を削除する関数です。

動作は、

(DEFVAR *STRING* (FORMAT NIL "~%foo~%~%~%   "))

*STRING*
⇒ "
foo


   "
(KL:STRING-TRIM-WHITESPACE *STRING*)
;⇒ "foo"

定義は、

(defun string-trim-whitespace (str)
  (string-trim *whitespace-chars* str))

となっています。

このSTRING-TRIM-WHITESPACEのことより、標準でSTRING-TRIMというものが用意されていたことの方に感心してしまいました。

[gdb] GDB において特定の回数関数が呼ばれたら break する

GDB において特定の回数関数が呼ばれたら break する方法。

# break point を表示。番号を知る
(gdb) info b
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x0000000000413fab in scheme::VM::runLoop(scheme::Object*, __jmp_buf_tag*, bool) at src/VM-Run.cpp:982
2       breakpoint     keep y   0x000000000040e240 in scheme::VM::tryJitCompile(scheme::Object) at src/VM.cpp:957
	breakpoint already hit 3 times
# 2番の breakpoint において 121 回は通過し 122 回目で break するように指示
(gdb) ignore 2 121
Will ignore next 121 crossings of breakpoint 2.
(gdb) r

事前に 122 回目の呼び出しで値がおかしくなる事が分かっている場合に上のようにデバッグする。

[mosh] Mosh 0.2.3 リリース

メンテナンスリリース。S式のシリアライズ(Fasl)が循環リストなどを正しく読み書きできるようになりました。

http://code.google.com/p/mosh-scheme/

Emacs上でGaucheのinfoを引く

shiroさんに教わったのでメモっておきます

;;; from shiro
(defun gauche-info-index (topic)
  (interactive
   (list (read-string
	  (concat "Gauche help topic : ")
          (current-word))))
  (switch-to-buffer-other-window (get-buffer-create "*info*"))
  (info "/usr/share/info/gauche-refe.info.gz")
;;(info "/usr/local/share/info/gauche-refe.info.gz") ;;うちは/usr/local/

  (Info-index topic))

;;(define-key global-map "\C-xH" 'gauche-info-index) ;; original
(define-key global-map "\C-x\C-j" 'gauche-info-index) ;; naoya_t

キーバインドは C-x H だとシフト押すのが面倒なので、うちでは C-x C-j に移しました。(キーバインドは皆さんのお好みで!)

調べたい関数名の後でC-x C-jするとinfoが引けます。これは便利。

TLE (Time Limit Exceeded) 2010

去年ちょっとだけ参加したTLE (Time Limit Exceeded)に今年は最初から参加。とは言っても仕事の合間にちょこちょこと。

  • PALIN1 (Super Palindrome - 1; 問題文): 58.7356 / 100
     // n^n%p。要128bit演算
  • PALIN2 (Super Palindrome - 2; 問題文): 111.6 / 150
     // これは簡易版
  • PREP (The Preprocessor Problem; 問題文): 5.6684 / 100
     // これは浜地さんの出題だそうです
     // cpp(プリプロセッサ)でfizzbuzz。あとでじっくり考えたい
  • CARM (Carmichael Numbers; 問題文): 3.2305 / 100
     // 自作Bignumが遅くてTLE(文字通りの)との闘い
  • COMP (Compress the Text/Image; 問題文): 76.973 / 100
     // tsubosakaさんさすがと思った
  • SHORTEN (Play with Code; 問題文): 18.2888 / 100
     // コードちゃんと読んでないので時間あればもっと取れたはず
  • KEY (Key to C; 問題文): 69.4118 / 100
     // 問題の意味がわからず悩んだ
  • CQUINE (Chain Quine!; 問題文): 94.2466 / 200
     // quineが書けただけで満足っす

(追記:恥ずかしいコードへのリンクを貼りました)

とりあえず通るコードを考えてsubmit x 8で最速全問通過(別にボーナスは無い)。しかしその後の詰めの能力は低いので順位は上がらず。瞬間最高順位は2位。

最終結果は438.1527点で19位。別枠でランキングのあるインド人トップより辛うじて上だけどそんなの関係ない。これはインドを舞台にした日本人同士の闘い。

パズル的にはとても面白かったけれどやはりゴルフ力が全然ないので、渋谷から10分のゴルフ場で鍛えるなどしたいです。

おまけ:副次的効果

[mosh] Mosh 0.2.2 をリリースしました

f:id:higepon:20090503135328p:image

Mosh 0.2.2 をリリースしました。ソースコードダウンロード


バグ修正がメインのメンテナンスリリースです。また id:mjt さんによって IrRegex が移植されました。

リリースの詳細

[メモ]Gaucheで書いた関数をErlangから呼び出す

gistに貼ってるだけだと忘れそうなのでここにもメモっとく。

「プログラミングErlang」の§12.2 に、ErlangからCの関数を利用する方法があるので、同等なインターフェイスを書けば

(define (twice x) (* 2 x))
(define (sum x y) (+ x y))

のようなScheme(Gauche)の関数も呼び出せる。

Eshell V5.7.4  (abort with ^G)
1> c(example1).
{ok,example1}
2> example1:start().
<0.39.0>
3> example1:twice(48). 
96
4> example1:sum(17,25).
42
...
続きを読む
今日のあうとぷっつ
S式を1つも書いてない…
2010/2/8 の Outputz
原稿用紙 36.7枚(14,676文字)

powered by Outputz.

C.M.ビショップ「パターン認識と機械学習(PRML)」読書会#11

【C.M.ビショップ「パターン認識と機械学習(PRML)」読書会の情報はこちら

8章後半~9章の最初@サイボウズラボにて

 §8.4 グラフィカルモデルにおける推論

   マルコフ連鎖、因子グラフ

 §9.1 K-meansクラスタリング

次回読書会は3/7(日) サイボウズ・ラボにて§9.2~§10.1。

予約(※キャンセル待ち状態!)はATNDから。

単語の難易度を取得する API

iVoca で単語の難易度を取得する API を試験リリース(項目反応理論) - Mi manca qualche giovedi`?


これは Scheme コードバトンで使えそうだ。易しい順に出題とかできる。

Interpolative coding (via "tsubosakaの日記") - (1)C++編

Interpolative coding - tsubosakaの日記 より。

長さと出てくる値の最小値、最大値が分かっている狭義単調増加な自然数のリストを圧縮する方法の話。

最小値1、最大値20、長さ7の数列 [ 3, 8, 9, 11, 12, 13, 17 ] が17ビットに圧縮されるらしい。試してみたい。

まずはC++に翻訳しつつ写経。(Scheme編はこちら

続きを読む
Interpolative coding (via "tsubosakaの日記") - (2)Scheme編

Schemeでも写経してみたの巻。C++編はこちら

#;'(べ、べつにS式で書かないと理解できないわけじゃないんだからね)

(define (lg x) (integer-length (- x 1)))

(define (interpolative-encode L L-length lo hi)
  (define (binary-encode x low high result)
    (let* ([range (+ (- high low) 1)]
           [bnum (lg range)]
           [enc (- x low)])
      (let loop ((i (- bnum 1)) (result result))
        (if (< i 0) result
            (loop (- i 1) (cons (if (logbit? i enc) 1 0) result))))))
  (define (iter f lo hi left right result)
    (cond [(= f 0) result]
          [(= f 1) (binary-encode (vector-ref L left) lo hi result)]
          [else
           (let* ([h (quotient f 2)]
                  [m (vector-ref L (+ left h))]
                  [f1 h]
                  [f2 (- f h 1)])
             (iter f2 (+ m 1) hi (+ left h 1) right
                   (iter f1 lo (- m 1) left (+ left h)
                         (binary-encode m (+ lo f1) (- hi f2) result))))]))
  (let1 L-length (vector-length L)
  (reverse! (iter L-length lo hi 0 L-length '())))


(define (interpolative-decode L L-length lo hi input-stream)
  (define (binary-decode low high iter)
    (let* ([range (+ (- high low) 1)]
           [bnum (lg range)])
      (let loop ((i 0) (dec 0) (iter iter))
        (if (= i bnum)
            (values (+ low dec) iter)
            (let1 b (car iter)
              (loop (+ i 1) (+ (* dec 2) (car iter)) (cdr iter)))))))
  (define (iter f lo hi left right input-stream)
    (cond [(= f 0) input-stream]
          [(= f 1)
           (receive (m stream) (binary-decode lo hi input-stream)
             (vector-set! L left m)
             stream)]
          [else
           (let* ([h (quotient f 2)]
                  [f1 h]
                  [f2 (- f h 1)])
             (receive (m stream) (binary-decode (+ lo f1) (- hi f2) input-stream)
               (vector-set! L (+ left h) m)
               (iter f2 (+ m 1) hi (+ left h 1) right
                     (iter f1 lo (- m 1) left (+ left h) stream))))]))
  (iter L-length lo hi 0 L-length input-stream))

(define (main args)
  (let* ([L #(3 8 9 11 12 13 17)]
         [lo 1]
         [hi 20]
         [L-length (vector-length L)]
         [Ldec (make-vector L-length)]) ; 結果格納用vec
    (print "original: " L)
    (let1 encoded-bitstream (interpolative-encode L L-length lo hi)
      (format #t "encoded (~d bits): ~a\n" (length encoded-bitstream) encoded-bitstream)
      (interpolative-decode Ldec L-length lo hi encoded-bitstream)
      (print "decoded: " Ldec))))

結果

original: #(3 8 9 11 12 13 17)
encoded (17 bits): (0 1 1 1 1 1 0 0 1 0 0 0 0 0 0 1 1)
decoded: #(3 8 9 11 12 13 17)

17bitに圧縮後、ちゃんと復号できて一安心。

[book] プログラミング Clojure

(株)オーム社の森田さまより プログラミングClojure を献本いただきました。ありがとうございます。


Clojure を初めて知ったのは本書の訳者でもある Shiro さんの日記だったと記憶している。JVM 上で動く Lisp であること、言語デザインが優れている事などが挙げられていたように思う。その後 Clojure の名前は Hacker News などでたびたび見かけるようになり、気になっていたのだが本書が出版されるまで自分で触ってみる事はなかった。「新しいテクノロジへの追随は週に1-2時間でよろしい」という Rod Johnson の教えを守っている時期でもあったし。


本書はそんな Clojure がどんな言語であるかを教えてくれる貴重な日本語の書籍である。Lisp プログラマも、 Lisp になじみもない Java プログラマも何回もニヤリとする場面に遭遇すると思う。


Clojure への第一印象は「ああ。これは本気だな。本気の Lisp だ」というもの。読みながらメモした大小の特徴からもその本気が見えてくると思う。

  • 短い識別子
  • JVM べったりの構造
    • 最適化は JVM に任せてしまう
  • 各種データ構造のリテラル(マップ、セット、正規表現)
  • 変更不可データ
  • doc 関数の存在
  • Java の呼び出しの簡単さ
  • 型ヒントによる性能向上
  • シーケンスの導入
  • 並行プログラムへのアプローチ

自分は Clojure と Scheme の差分に着目して読み進めたが、「そうそう。やっぱりあれがないと話にならないよね」というものきちんと認識して組み込みで提供している。勝手な印象だが、Shiro さんの Gauche に良く似ていると思う。丁寧な作り込みと、実践や経験からくる組み込み機能提供のバランスの部分とか。


Clojure が Scala などとともに今後普及するかどうかは、現時点では怪しいと思うがそれでも野心的な Lisp 処理系なことには間違いない。Java 案件があったらこっそり Clojure で書いてみたいと思った。

しかし JRuby しかり Clojure しかり、JVM に乗っかった処理系たちは勢いがある。Clojure における再帰問題のように JVM も完璧ではないのだが、JVM に乗っかる事で得られる利益は僕が考えているよりは大きいのだろうな。


ちなみに Scheme が読み書きできるならば、以下の 2 つのコードを見比べてみると手っ取り早く Clojure との違いの雰囲気を知ることをできる。


プログラミングClojure

(info symbol):Gaucheでinfoドキュメントから該当ページを表示する

こんな便利なものがあるなんて知らずに生きていた(恥)

Function: info symbol

Gaucheのinfoドキュメント中から、 symbolで指定される手続きか構文要素の定義を含んでいるページを表示します。 infoドキュメントは、もし環境変数INFOPATHが定義されていればそこに示されるディレクトリ中から探され、そうでなければgoshのライブラリディレクトリから推測されるディレクトリ中から探されます。infoドキュメントが見付からなかったり、見付かってもsymbolがIndexページ中に無かった場合はエラーとなります。つまり、この手続きはinfoファイルがインストールされていないと動作しません。

現在の出力ポートが端末である場合、infoドキュメントの該当ページはページングプログラムを用いて表示されます。環境変数PAGERが指定されていればそれを用い、そうでなければコマンドサーチパスからless及びmoreをこの順で探します。いずれも見付からなかった場合や、出力ポートが端末ではない場合には、単にページがそのまま出力されます。

この手続きのセッション中での最初の呼び出しは、infoファイルをパーズするために多少時間がかかります。

info - gauche.interactive

unfoldの引数の順番に迷った時とか、REPLから

gosh> (info 'unfold)

と打てば

10.2.5 List fold, unfold & map
------------------------------

...
... (foldとかreduceとかの定義) 
...

 -- Function: unfold p f g seed &optional tail-gen
     [SRFI-1] Fundamental recursive list constructor.  Defined by the
     following recursion.

          (unfold p f g seed tail-gen) ==
             (if (p seed)
                 (tail-gen seed)
                 (cons (f seed)
                       (unfold p f g (g seed))))
     That is, P determines where to stop, G is used to generate
     successive seed value from the current seed value, and F is used
     to map each seed value to a list element.
...

qを打てばまたREPLに戻って来られる。これは便利。

[mosh] Mosh バグ修正2件

id:leque さんがバトンきっかけで発見・修正してくださった物。ありがたい。

Snow LeopardでGauche-mecab

久々にMeCabを使いたくなったのでGauche-mecabをインストールしたい(が少しはまった)のでメモ。

1. ビルドはGauche-0.9でもSnow Leopardでも行けるっぽい。

  • CFLAGS='-arch i386' LDFLAGS='-arch i386' ./configure とかしなくても可か

2. ビルドはできるが make check で失敗する。

  • /usr/lib/にある、Snow Leopardに元々入ってる?MeCabを見に行ってしまうため。
mecab-lib.$(SOEXT): $(srcdir)/mecab-lib.scm
    $(GENCOMP) --ext-module=text/mecab.scm $(srcdir)/mecab-lib.scm
    $(GAUCHE_PACKAGE) compile \
      --local=$(LOCAL_PATHS) --ldflags='-L/usr/local/lib' --libs='-lmecab' --verbose mecab-lib mecab-lib.c

のようにldflagsでなんとかすれば良いレベル。

Schemeコードバトン(の本流の方)が回ってきた【後編】:c-wrapperをSnow Leopardでビルドする

やったこと

  • 同じスクリプトをGaucheでもmoshでも動かそうと試行錯誤
    • cond-expandを使うにはmoshではimport文が先に必要
    • とりあえず、Gaucheで動かしたい時には最初のimportをコメントアウト、な方式で行きます
  • 途中で2つの大きな壁
    • moshをSnow Leopardで動かす →前編参照
    • c-wrapperをSnow Leopardで動かす →c-wrapperは32bitでならビルドする方法が見つかった。後述。
  • 小さな壁
    • ncurseswが文字化け → LC_ALL の値が環境依存?とりあえず6を0にしたらMacでは直ったっぽい
続きを読む
Schemeコードバトン(の本流の方)が回ってきた【前編】:moshをSnow Leopardでビルドする

higeponさんから始まったコードバトン、のSchemeブランチ(というか本流)がkazu634さんから回ってきた。

コードがmoshべったりになってるので、とりあえずmoshで動かしてみるか。

と思ったらこのマシンにはmoshが入っていない。

HEADを入れるにしてもmosh-0.2.0が要るみたいなので0.2.0を貰ってきて

$ ./configure
checking build system type... i386-apple-darwin10.2.0
checking host system type... i386-apple-darwin10.2.0
checking target system type... i386-apple-darwin10.2.0
checking for a BSD-compatible install... /usr/bin/install -c
...
configure: error: GNU MP not found, see http://gmplib.org/."For OSX, install GNU MP with "CFLAGS+=-m32 ./configure ABI=32 && make"

これは見たことありますね。GNU MPが入ってない旨のメッセージ。

続きを読む
Schemeコードバトン(のCL fork)に参加しました

higeponさんから始まったコードバトンに参加。なぜかCommon Lispフォークの方に呼ばれた…

snmsts: 誰もアイデアが無いんだったら自薦者としてはmasatoiさん他薦として higepon(敬称含む)を推します。> naoya_tさん 個人的にはschemerを舐めていきたい。 (※下線は筆者)

Chaton COMMON LISP JP

SchemerとCLerの生暖かい交流(というか人材の奪い合い)が心に残ります。

やったこと

登録された単語からの検索機能 (hige:pan) を実装しました。

  • で、バトンもらったけどこれどうやって動かすのか
  • Snow LeopardにアップグレードしてからCL使ってなくて動かない><
  • sbcl をインストールし直した
  • sbcl にどうやって食わせるんだっけ
$ sbcl
This is SBCL 1.0.29, an implementation of ANSI Common Lisp.
More information about SBCL is available at <http://www.sbcl.org/>.

SBCL is free software, provided as is, with absolutely no warranty.
It is mostly in the public domain; some portions are provided under
BSD-style licenses.  See the CREDITS and COPYING files in the
distribution for more information.
* (load "scheme_baton.lisp")
; ...

T
* (in-package :cl-user)

#<PACKAGE "COMMON-LISP-USER">
* (in-package :hige)

#<PACKAGE "HIGE">
* 

(pon) (pin) (pun) とかして遊べるようになります。

  • 辞書から単語をassocしてくるだけの関数 search-dict の実装
  • 単語を入力し、search-dict で検索し、見つかれば意味を、見つからなければ "Not found." と返すだけの hige:pan を実装
  • aifマクロを追加(というか "On Lisp" からコピペ)
  • (loop :for ... :in ... :do ...)dolist で置き換えてみた

以下diffです:

続きを読む
PR: 1月22日発売

(via @finalfusion)

郵便事業株式会社は、平成17年(2005年)にシリーズが始まり、数々の人気アニメを題材としてきた「アニメ・ヒーロー・ヒロインシリーズ」の第12集「ケロロ軍曹」を発行いたします。

特殊切手「ケロロ軍曹」の発行 - 日本郵便

これはぜひ欲しいですね。

[scheme] Scheme コードバトンまとめページ

バトン参加表明中

Scheme

  1. id:higepon: 第1回 Scheme コードバトンのお知らせ
  2. id:yad-EL さん: Schemeコードバトンに参加しました - ヤドカリデンキ商会(第一倉庫)
    • gist: 273551 - GitHub
    • さっそくバトンの醍醐味であるダイナミックな書き換えが発揮され Gauche 向けに書き換えられました。second -> cadr ですが個人的には first, second が好き。 Gauche なら (use srfi-1) 。入出力のバッファリングは確かにはまるポイントかも。call/cc はわざと入れているので勇者が読み解いて(おおげさだ)変更してくるのも面白いかも。
  3. Ryohei Ueda (garaemon) さん:garaemon.net » Blog Archive » 第一回schemeコードバトン(garaemon fitst time編)
    • gist: 274082 - GitHub
    • かなりの変更が加えられています。自分も読んで勉強になる。まず srfi 37 を使いコマンドラインオプションに対応しています。なんと英語のヘルプ -h まで付属。with-parsed-options を定義するあたりはさすが Common Lisper 。それにしても srif 37 って結構面倒なんですね。Gauche の let-args は簡単でよい。
  4. id:yshigeru さん: Schemeコードバトン〜1週目 - そーり日誌
    • gist: 274151 - GitHub
    • 侠気あふれる1文字変更。何というか遊びを心得ている。1周目とあるのでまた回ってくるのを期待されているのかもしれない。
  5. id:g000001 さん: Schemeコードバトンに参加しました R6RS編 - わだばLisperになる - cadr group
    • gist: 274246 - GitHub
    • あっさりと call/cc の削除に成功しています。g000001 さんがコード書けないという噂は嘘だ!。append-reverse 知りませんでした。使う機会がたくさんありそうなので覚えておきます。
  6. id:masa_edw さん: コードバトン - masa.edw the ハバネロブリーダー
    • gist: 275132 - GitHub
    • 自分の環境では sudo apt-get install libncursesw5-dev が必要でした。FFI をあっさり使ってもらえた事に感動。これは大きな飛躍で Scheme の外の世界とやりとりできる事になるので幅が広がる。ソースコード中に FFI 使用例があると次の人はそれを参考にしやすいからこれ以降爆発するかも。curses を FFI で呼び出すという発想が自分には無かったのでこれもバトンをやって良かった。予想外。操作感を良くするという改善はなかなか出来ないので素直に感心。mallocはこちらだと呼び出せるので謎。なんだろう。libc のロードは (open-shared-library "") で良いかも。
  7. id:lequeさん: Scheme コードバトン - 月の塵
    • gist: 276799 - GitHub
    • 良いタイミングで良い人にバトンが渡った印象。各個人が個性を発揮して書きだしたコードにまとまりが無くなってきたのをきれいにしてくれた。大きいところではテストがあるとか細かいところではアクセサをちゃんと書くとか。一番ニヤリとしたのは try-finally かな。バグ登録もししてもらったので直さねば。syntax-rules の ?pat は確かに可読性が高そう。今度やってみる。hoge と hoge* は完全に定着してしまった。(複数形を考えなくて良いから)
  8. emasaka さん: 本を読む Schemeコードバトンに参加しました
    • http://gist.github.com/276917
    • 逆引きが追加された。今まで誰も実装していなかったのが不思議。swap! って何だと思ったらマクロだった。こういう使い方は自分はしないから面白いなー。さっそくテストが追加されていて leque さんの土台に乗っかっています。タイムアウトってどうやって実現しているんだろうと疑問だったが ncursew にあるのか。FFI 素晴らしい。
  9. kazu634 さん: 2010-01-17 - 武蔵の日記
    • http://gist.github.com/278675
    • kazu634 さんって武蔵さんか。634 なるほど。ツールの目的は何か?にきちんと着目して改善されているのが素晴らしい。覚えたはずの単語を忘れる可能性を考慮して日付データを追加している。word-spec-date だけ fifth になっててふいた。やっぱ cad..dr より srfi-1 だよね。word-spec-crteria で足し算を使っているのが面白かった。
  10. naoya_t さん: 紫ログ:Schemeコードバトン(の本流の方)が回ってきた【後編】:c-wrapperをSnow Leopardでビルドする - livedoor Blog(ブログ)
    • http://gist.github.com/279595
    • Gauche と Mosh の両方で動くようにという変更。Mosh on Snow Leopard のビルドに苦労されたようで申し訳ない。手元に環境がないとなかなか。srfi-0 に cond-expand という仕組みがあってあれこれです。Gauche は use をファイルの先頭でないところにも書けるんですね。Gauche 用に parameters が一式コピペされてて面白かった。力技だ。他の処理系で動かそうとすると、各所理系の特色が見えるのが面白いですね。
  11. snmsts さん
  12. id:scinfaxi さん Scheme コードバトン - れいめいにっき
  13. id:Gemma さん SchemeコードバトンをGaucheでCGIにしてみた - Gemmaの日記
  14. torus さん http://twitter.com/torus/status/8260524063
  15. (び) さん http://twitter.com/bizenn/status/8409198193
  16. nobsun http://twitter.com/nobsun/status/8493438985
  17. id:koguro さん http://d.hatena.ne.jp/koguro/20100207/1265532826

Common Lisp

  1. id:g000001 さん: 第1回 Scheme コードバトンのお知らせ - わだばLisperになる - cadr group
    • gist: 273441 - GitHub
    • REPL になってる。defstruct が CL っぽい印象。噂の loop を発見。へぇ。こうやって書くのか。#'> の #'ってなんだ?クォート?prog2 は begin0 の親戚か。コードがとてもきれいな印象を受けました。

Clojure

  1. 噂の「英単語を覚えるスクリプト」をClojureで - athosの日記

Scheme (バトンではないがいじってくれた)

Smalltalk

[scheme] 第1回 Scheme コードバトンのお知らせ

Scheme のコードをバトンのように回していき面白い物ができあがるのを楽しむ遊びを始めました。

盛り上がるようであれば次回 Shibuya.lisp で成果を発表したいと思っています。


もしご興味のある方がいらっしゃいましたら、コメントで表明していただくとバトンが回ってくる対象となります。

とても短いコードをいじっていくので Scheme 初心者の方でも参加歓迎です。(分からない事があればフォローします。)


詳細はこちらをどうぞ。http://gist.github.com/273431


現在 higepon -> yadokarielectri さんとバトンが渡っています。

現在参加表明している方々

g000001 さん、yshigeru さん、garaemon さん、yadokarielectri さん、leque さん

他のバトン

Common Lisp バトンの動きもあるようです。どちらが面白い物を作れるかな。

Schemer と CLer の蔑称

garaemon さんの表現が面白い。

  • Schemer → 再帰バカ
  • CLer(Common Lisper) → 副作用バカ

愛すべきバカだなあ。

http://twitter.com/garaemon/status/7588113347

C.M.ビショップ「パターン認識と機械学習(PRML)」読書会#10
【C.M.ビショップ「パターン認識と機械学習(PRML)」読書会の情報はこちら

8章(グラフィカルモデル)前半@サイボウズラボにて

 §8.1 ベイジアンネットワーク
 §8.2 条件付き独立性
 §8.3 マルコフ確率場

ICMより綺麗にノイズ除去が出来るらしいグラフカットアルゴリズムが気になる。§8.3のtsubosakaさんの発表で参考文献として挙げられていたグラフカットのチュートリアル(日本語)ぐらいは目を通したい。

次回読書会は2/6(土) サイボウズ・ラボにて§8.4~§9.1。
予約はATNDから。
[mosh] Shibuya.lisp に向けて Scheme コードバトンするのはどうか?

次回 Shibuya.lisp のネタ。「英単語覚えるスクリプト」のように短くていじりやすいコードを github に置いてコードバトンをするのはどうかな。ルールは2つ

  • 自分がこれだ!と思える変更を2日以内にコードに加える。人に優しい変更なら何でも良い。1文字の変更でも可。
  • 次の人にまわし、コードが変更されるのを見守る。

次回 Shibuya.lisp までこのバトンをまわしておくとあっと驚く物ができるんじゃないかな。あと初心者の人でもいじりやすいように、twitter の shibuya.lisp アカウントに質問してくれれば何でも答えるというサポート体制を置くとか。


Scheme を触る良いきっかけになればと思うんだけど、どうですか?やりたい人いるかな?

[mosh][scheme] 英単語覚えるスクリプト

Shibuya.lisp の発表で少し触れた、英単語覚えるスクリプトを改善した。毎日使っていて単語量が増えたので誤り回数が多い物順に出題する事にした。

(import (rnrs)
        (mosh control)
        (mosh)
        (match)
        (mosh file)
        (srfi :8)
        (only (srfi :1) first second))

(define (sort-word-spec* word-spec*)
  (list-sort
   (match-lambda*
    [((_a _b ok-count1 ng-count1) (_c _d ok-count2 ng-count2))
     (> (- ng-count1 ok-count1) (- ng-count2 ok-count2))])
   ;; normalization
   (map (match-lambda
          [(word meaning)
           (list word meaning 0 0)]
          [(word meaning ok-count ng-count)
           (list word meaning ok-count ng-count)])
        word-spec*)))

(define (main args)
  (let1 result*
      (call/cc
       (lambda (break)
         (let loop ([word-spec* (sort-word-spec* (file->sexp-list (second args)))]
                    [result-spec* '()])
           (match word-spec*
             [() result-spec*]
             [((word meaning ok-count ng-count) . more)
              (format #t "~s: " word)
              (read (current-input-port))
              (format #t "~s y/n? " meaning)
              (case (read-char (current-input-port))
                [(#\y #\Y)
                 (loop more (cons (list word meaning (+ ok-count 1) ng-count) result-spec* ))]
                [(#\N #\n)
                 (loop more (cons (list word meaning ok-count (+ ng-count 1)) result-spec*))]
                [(#\q #\Q)
                 (break (append (reverse result-spec*) word-spec*))])])]))
    (call-with-port (open-file-output-port (second args) (make-file-options '(no-fail)) 'block (native-transcoder))
                    (lambda (p)
                      (for-each (lambda (x)
                                  (write x p)
                                  (newline p)) result*)))))

(main (command-line))

match-lambda を使っているのは Erlang で便利さに気づいたから。

[mosh] JIT コンパイルが再帰して困った

JIT コンパイラが Scheme で書かれているので、JIT コンパイラ自身も JIT コンパイルされる可能性があることに気付いた。そうすると

  1. 手続き A を JIT コンパイルしようとする。
  2. JIT コンパイラ中の手続き B が閾値を超えて call される。
  3. 手続き B を JIT コンパイルしようとする。
  4. JIT コンパイラ中の手続き B が閾値を超えて call される。
  5. 手続き B を JIT コンパイルしようとする。

と繰り返されてしまう。同じ手続き B が再帰的に何回も JIT コンパイルされるのが問題なので、手続き B にコンパイル中フラグをつければ良いかと思ったがそうも行かない。

例えば以下のような場合を考えれば分かる。

(define (jit-compile x)
  ...
  ...
  (map (lambda (x) (+ x 2)) lst)
  ...)

手続き B が (lambda (x) (+ x 2)) だとすると jit-compile の呼び出し毎に、新しい手続きがアロケーションされるので、ソースコード上は同じ手続きでも実行時には別の手続きなのだ。(コンパイラが賢ければ、(lambda (x) (+ x 2)) を静的にくくりだす事も可能だがそれはまた別の話なので置いておく)


上記のような事情から、JIT コンパイラは再帰的に起動しない。グローバルで JIT コンパイル中フラグを持つ。という方針にしようかと思う。ただし欠点があって良く呼ばれるであろう JIT コンパイラ自身が JIT の恩恵を受けられない。

もっと良い方法はないだろうか。

iPhoneアプリから投稿テスト

livedoor blogのiPhoneアプリが出たので投稿してみます。

してみました。

http://blog.livedoor.jp/staff/archives/51370750.html

Recent conditions

ここしばらく本体となるピンボールゲームの開発に忙しくイプシロン関連の更新が滞っております :(

新タイトル「MAD DAEDALUS(仮称)」が完成しましたら、その成果をイプシロンにフィードバックいたします、どうぞしばらくお待ち下さい m(_ _)m

[Inside Ypsilon][Scheme][shibuya.lisp]JelloBench - A practical garbage collection benchmark program

Shibuya Lisp TT#2の発表の時に使った"JelloBench"です :)
テクスチャマッピングされたポリゴンをSDL/OpenGLで描画しています。
プログラムはすべてSchemeで書かれていますが、Intel Core2 2.4GHzのLinuxで3500フレーム/秒以上の表示が可能です。

D

JelloBenchの実行には開発版のイプシロン(http://code.google.com/p/ypsilon/)とSDL, SDL_image, SDL_mixerが必要です。MacOSXでは最初にSDL.framework, SDL_image.framework, SDL_mixer.frameworkをインストールしておいてください。インプシロンのビルド時にSDL初期化用のdylibが作成され/usr/local/lib/ypsilon/に自動的にインストールされます。

JelloBenchは'example'にカレントディレクトリを移動してから'ypsilon jello.scm'で実行してください。

今回追加したMacOSXのSDLサポートにはid:kazuya_aさんがypsilon+SDL+Mac OSX!に紹介された方法を使っています。これによりSDL専用のイプシロンをビルドする必要がなくなりました。感謝です!:)

(6/13追記:動画を再エンコードしました)

[Ypsilon API][Inside Ypsilon][Scheme]YpsilonがPS3で動くようになりました

野田 開さんのご厚意によりPS3をSSH経由で提供して頂きました m(_ _)m
32bit/64bit対応でFFIもサポート済みですよ。 :)

libspe2を使ったテストプログラムを作ってみました。
svn trunkのイプシロンをPS3に入れると動きます^^b

#!/usr/bin/env ypsilon
#!r6rs

;; ps3-cell-demo.scm
;; tested on PS3 Linux

(import (rnrs)
        (only (core) system format iota)
        (ypsilon ffi)
        (ypsilon concurrent)
        (ypsilon cell libspe2))

(define spe-code
  "
  #include <stdio.h>
  int main(unsigned long long spe_id, unsigned long long pdata) {
    printf(\"SPE:0x%llx sleep for 2 second\\n\", spe_id);
    sleep(2);
    printf(\"SPE:0x%llx exit\\n\", spe_id);
    return 0;
  }\n")

(define NULL 0)
(define source-file "spe_example.c")
(define object-file "spe_example")

(define make-spe-program
  (lambda ()
    (when (file-exists? source-file) (delete-file source-file))
    (call-with-port
      (open-output-file source-file)
      (lambda (port)
        (put-string port spe-code)))
    (unless (= (system (format "spu-gcc ~a -o ~a" source-file object-file)) 0)
      (error 'make-spe-program "unexpected error"))))

(make-spe-program)
(newline)

;; sequential

(let ((image (spe_image_open object-file)))
  (when (= image NULL) (error 'spe_image_open "unexpected error"))
  (for-each (lambda (n)
              (let ((context (spe_context_create (+ SPE_EVENTS_ENABLE SPE_MAP_PS) NULL)))
                (when (= context NULL) (error 'spe_context_create "unexpected error"))
                (spe_program_load context image)
                (let ((entry (make-c-int SPE_DEFAULT_ENTRY)))
                  (format #t "-- kick sequential run ~a/6\n" n)
                  (when (< (spe_context_run context entry 0 0 NULL NULL) 0)
                    (error 'spe_context_run "unexpected error"))
                  (spe_context_destroy context))))
            (iota 6))
  (spe_image_close image))

(newline)
(newline)

;; parallel

(let ((image (spe_image_open object-file)))
  (when (= image NULL) (error 'spe_image_open "unexpected error"))
  (let ((threads
         (map (lambda (n)
                (format #t "-- kick parallel run ~a/6\n" n)
                (future
                 (let ((context (spe_context_create (+ SPE_EVENTS_ENABLE SPE_MAP_PS) NULL)))
                   (when (= context NULL) (error 'spe_context_create "unexpected error"))
                   (spe_program_load context image)
                   (let ((entry (make-c-int SPE_DEFAULT_ENTRY)))
                     (when (< (spe_context_run context entry 0 0 NULL NULL) 0)
                       (error 'spe_context_run "unexpected error"))
                     (spe_context_destroy context)))))
              (iota 6))))
    (format #t "== wait for all SPE exit\n")
    (for-each (lambda (x) (x)) threads))
  (spe_image_close image))

このプログラムは、最初に一つのSPEで順次実行し、次に6個のSPEで並列実行します。

$ ypsilon example/ps3-cell-demo.scm 

-- kick sequential run 0/6
SPE:0x101b4340 sleep for 2 second
SPE:0x101b4340 exit
-- kick sequential run 1/6
SPE:0x101b4340 sleep for 2 second
SPE:0x101b4340 exit
-- kick sequential run 2/6
SPE:0x101b4340 sleep for 2 second
SPE:0x101b4340 exit
-- kick sequential run 3/6
SPE:0x101b4340 sleep for 2 second
SPE:0x101b4340 exit
-- kick sequential run 4/6
SPE:0x101b4340 sleep for 2 second
SPE:0x101b4340 exit
-- kick sequential run 5/6
SPE:0x101b4340 sleep for 2 second
SPE:0x101b4340 exit

-- kick parallel run 0/6
-- kick parallel run 1/6
-- kick parallel run 2/6
-- kick parallel run 3/6
SPE:0x101b5230 sleep for 2 second
SPE:0x101b5170 sleep for 2 second
SPE:0x101b52f0 sleep for 2 second
SPE:0x1020c248 sleep for 2 second
-- kick parallel run 4/6
-- kick parallel run 5/6
== wait for all SPE exit
SPE:0x10223910 sleep for 2 second
SPE:0x10237e48 sleep for 2 second
SPE:0x101b5230 exit
SPE:0x101b52f0 exit
SPE:0x101b5170 exit
SPE:0x1020c248 exit
SPE:0x10223910 exit
SPE:0x10237e48 exit

うまく動いているようです :D

ところでpowerpcはわたしの好きなCPUの一つなのですが、やはりあのニーモニックは微妙・・・思い出せばなんでもないことなんですけどね :p

SSH経由なのでエディタはemacsを使いました。どこでも同じものが動くというのは素晴らしいことです!でも・・・あいかわらず・・・普段はほとんど使っていません(笑

[Ypsilon API][Scheme]SDL_ttfのバインディングを追加しました

f:id:fujita-y:20090509122835p:image:w166

example/sdl-ttf-demo.scmの表示です :)

[Ypsilon API][Scheme]MySQLのバインディングを追加しました

やっぱりハッシュテーブルだけだとキツイです・・・
で、餅は餅屋ということでMySQL 5.1 C APIのバインディングを追加しました。

$ ypsilon
Ypsilon 0.9.6-trunk/r443 Copyright (c) 2009 Y.Fujita, LittleWing Company Limited.
> (import (ypsilon mysql))
> (define NULL 0)
> (define user "root")
> (define passwd "...")
> (define mysql (mysql_init NULL))
> (if (zero? (mysql_real_connect mysql "localhost" user passwd "mysql" 0 NULL 0))
      (display (mysql_error mysql))
      (display (mysql_stat mysql)))
Uptime: 52318  Threads: 1  Questions: 7  Slow queries: 0  Opens: 12  Flush tables: 1 ...
> (mysql_close mysql)

このままだと使いにくいので何か考えたいですね :)