Syntax highlighter

2015-11-30

S式SQL その2

ちょっと書き始めたらいきなり壁にぶち当たったのでSQL恐ろしい子という感じである。

SQLにはqualified identifierというものがある。何かといえば「.」で繋げられたあれである。例えば以下のSQLをS式にするとする:
select f.bar from foo f;
特に何も考えなければ以下のようになるだろう。
(select (f.bar) (from (as foo f)))
asをつけるかどうかは決めてない(SQL的には要らない子でもS式的にはあった方がいいような)。大抵の場合はこれで問題ないんだけど、SQLにはdelimited identifierというものがある。例えばこんなにも合法なSQL:
select f."bar" from foo f;
SchemeにはR7RSから「||」が入ったんだからdelimited identifierもそれでいいじゃん?と思わなくもない。S式からSQL文字列にした際にどうするとか考えなければだけど。

ここまではまだ序の口で、少なくともSQL2003からはユニコードが使えて、以下のようなのも合法:
select f.U&"\0062ar" from foo f;
大分怪しくなってきた。さらにエスケープ文字の変更も可能なので、以下のも合法:
select f.U&"$0062ar" uescape '$' from foo f;
誰が書くんだこんなのというレベルだが、テーブルやカラム名にASCII以外を使っているとありえるのかもしれない。さらに、U&"$0062ar" uescape '$'はunicode delimited identifierというトークンなので、単なる識別子として処理される。つまり、末尾である必要がなく、以下も合法:
select U&"$0066" uescape '$'.U&"$0062ar" uescape '$' from foo f;
涙出そう。ここまで行くと全てを捨ててシンボルでというわけにはいかないので、SQLの読み込みで作られるqualified identifierはリストにすることにした。こんな感じ:
(select ((@ (unicode (! "$0066") uescape "$") (unicode (! "$0062ar") uescape "$"))) 
 (from (as foo f)))
果てしなく冗長な気がする。連結を表すのに「@」を使うか悩み中。「.」が使えるといいんだけど、「|」でエスケープしたくない。ただ、「@」は別のところで使いたい場面が出てきそうな上に、今一連結(もしくは参照)というイメージが湧かない。「->」はSQLのキーワードの一つなのでできれば使いたくない。「=>」だと紛らわしいかなぁ?

パーサー自体はゴリゴリとBNFを書いていくだけなので作業量は多いけどそこまで大変ではない(大変だけど)。必要な部分だけ書いて後は必要に応じてということができそう。やはり問題になるのはこういう細かい表記の部分だろう。一度使い始めると変更できない(したくない)部分になるので可能な限り違和感のないものにしたいところである。

追記:qualified indentifierをスロットアクセスと考えれば「~」を使うのはありかもしれないなぁ。後は連結に何を割り当てるか考えないとなぁ。

2015-11-27

S式SQL

ちょっと本格的に欲しくなってきたのでメモ兼考えをまとめる。

ことの発端は仕事でテーブルの変更を加えた際に200件を超えるINSERT文を修正しなければいけない可能性が出たこと。可能性で終わった(偶然僕は休みだったので)のだが、今後こういったケースが出ないとは限らない。というかDBを弄る必要がある以上起きる。毎回手作業で貴重な人生を浪費するのも馬鹿らしいので、プログラムにやらせてしまいたい。テキスト処理でやるには荷が重過ぎるのでAST(リストだけど)を操作したい。とここまでが動機。

SQLのBNFはここにあるのを使うとして(SQL2003と多少古いが問題ないだろう)、まずはどういう形にするかをまとめておきたい。これがまとまってないから頓挫してるリポジトリもあったりするし・・・

SQLをS式にするというのはいくつか既にあって、たとえばCL-SQLとかSxQLとかS-SQLとか、大体似てるんだけどちょっとずつ違う感じのS式を使用してる。例で挙げたのは全てCLなのでキーワードをSQLのキーワード、select等、に割り当ててるのもあるのだが、Schemeということでそれは避ける方向にする。キーワードでもいいんだけどリーダーのモードで読み込みが変わっちゃうので依存しないようにしたい。

いろいろ悩んだ結果こんな感じで割り付けることにする
  • 予約語:シンボル
  • テーブル名、カラム名(識別子):シンボル
  • 文字列:文字列
  • 数値:数値
  • ステートメント:リスト
  • 式:前置リスト
  • 関数呼び出し:前置リスト(式ではないもの)
いたって普通。単純なのはこんな感じに:
(select ((count *)) (from foo) (where (and (< 1 id) (< id 10)))
;; = select count(*) from foo where (1 < id and id < 10); 
他の文は適宜考えることにする。IS NOT NULLみたいなのはどうしようかなぁと悩み中。多分(not (null? ...))みたいにする。

パーサは軽く書いたけどずっと大変なんだよなぁ。BNFがあるのでpackratを使ってゴリゴリ書いていくつもりではあるが。とりあえず全く必要なさそうなEmbedded SQLとかはばっさり切ってしまって問題ないだろう。後は適当に何とかするしかないかなぁ。

割とすぐ欲しいけど時間がかかりそうだ。頑張ろう・・・

2015-11-19

R7RSのライブラリに関する疑問

R7RSを実装する際に、ライブラリ周りはR6RSを使いまわしにできたのであまりその仕様について深く考察したことがなかったのだが、最近ちょっと考えることがあり疑問というか不明瞭な点がいくつかあることに気付いた。具体的にはライブラリは複数回読み込まれる可能性があるというこの仕様が不明瞭な点を作っている。仕様から用意に読み取れる点から、ちょっと突っ込んだ(ら直ぐに不明瞭になる)点をだらだらと書いてみようと思う。

明示的に書いてある点

ライブラリAは複数のプログラム、ライブラリから読み込まれた際には読み込みが複数回に渡ることがある。
これは非常に簡単で、以下のようなものになる。
(define-library (A)
  (export inc!)
  (import (scheme base) (scheme write))
  (begin 
    (define inc! 
      (let ((count 0)) 
        (lambda () 
          (set! count (+ count 1))
          count)))
   )
)

(define-library (B)
  (export count-B)
  (import (scheme base) (A))
  (begin (define count-B (inc!)))
)

(define-library (C)
  (export count-C)
  (import (scheme base) (A))
  (begin (define count-C (inc!)))
)

(import (B) (C))

count-B
;; -> 1

count-C
;; -> 1 or 2
ライブラリBがインポートされるのが先と仮定すると、count-Cの値は未定義である。これはライブラリAが複数回評価される可能性があるからであり、これは明示的に書いてある。

書いてない点

いっぱいあるんだけど、とりあえず以下。
(import (scheme eval))

;; library (A) is the same as above
(eval '(inc!) (environment '(A)))
;; -> 1

(eval '(inc!) (environment '(A)))
;; -> ???
これ微妙に書いてない気がする。これは多分、2を返すのが正しい(はず)。根拠としては§5.6.1の最後にあるこれ:
Regardless of the number of times that a library is loaded, each program or library that imports bindings from a library must do so from a single loading of that library, regardless of the number of import declarations in which it appears. That is, (import (only (foo) a)) followed by (import (only (foo) b)) has the same effect as (import (only (foo) a b)).
environmentの引数はimport specである必要があるので、無理やり読めば上記に該当するような気がする。ついでに、プログラムの定義が一つ以上のimport句と式と定義されてる、かつライブラリが複数回読まれる可能性は、読み込みが複数のプログラムもしくはライブラリからなので。

気にしてるのはこれ
(import (scheme base) (prefix (scheme base) scheme:))
一つのプログラム内だから一回のみかなぁとは思うんだけど、微妙に読み取り辛い気がする。

これはどうなるんだろう?
;; a.scm
(import (A))
(inc!)

;; other file
(import (scheme load))
(load "a.scm")
(load "a.scm")
loadは同一の環境で評価するけど、二つのプログラムになるから、両方とも1を返してもいいのかな?それとも、loadで読み込まれたファイルは呼び出し元と同じプログラムということになるのだろうか?

まぁ、こんなことを考えているんだけど、実際の処理系で複数回ライブラリを評価するのは見たことがないので「完全処理系依存フリー」とかいうことをしなければ気にすることはないのではあるが。

2015-11-15

Defined or undefined?

R7RS doesn't mandate implementations to load a library only once, unlike R6RS. I believe, the reason why is that letting implementators to have variety of options such as without creating/storing library definition anywhere but each time it'd be evaluated. Understandable, just rather inefficient to me. Also it defines the behaviour of multiple import clauses of the same library.

Now, I've got a question. What should happen if there are 2 the same libraries import in the same import clause and one (or more) of the identifier(s) is(are) renamed like this?
(import (scheme base) (rename (only (scheme base) car) (car kar)))

;; are car and kar required to be the same binding?
Honestly, I couldn't read if it's required to be the same in such case from R7RS. Though my guess is the followings:
  • The last paragraph of section 5.6.1 only specifies the case of 2 import clauses importing the same libraries
  • This type of import can't be merged into one import in sense of R7RS import definition (or can it be?)
  • Thus this can be multiple import of the same library.
  • The third last paragraph of section 5.6.1 suggesting the possibility of multiple load when there's multiple import of the same library (can be interpreted as multiple evaluation of library).
The point that I'm not totally sure is that the paragraph which suggest the possibility of multiple load says that this would happen when the library is imported more than one program or library. This would also be interpreted if a library imported twice in the same script or library, then it should only be loaded once. If this interpretation is correct, then above car and kar must be the same bindings. Otherwise, can be different.

Why this matters? Generally, it doesn't. Just wondering if the last case of this Gist is required to print #t by R7RS.

I've also posted this question to comp.lang.scheme: this

2015-11-10

Explicit Renamingが解るかもしれない解説

R7RS-largeではExplicit Renaming(以下ER)が入ると噂されている。まだSRFIすら出ていないのでいつになるのか全く不明ではあるのだが、それがどのように動くかを理解しておけば近い将来(と信じたい)ERが入った際に慌てふためくこともないだろう。といってもsyntax-caseより遥かに簡単なので身構える必要もないのではあるが。

簡単な使い方

まずは簡単な使い方を見てみよう。例としてletをERで書いてみることにする。名前付letは考えないことにするのでマクロの名前はmy-letとしよう。また、簡便にするため既存のletを使うことにする。
(import (scheme base))
;; import er-macro-transformer
(cond-expand
  (gauche (import (gauche base)))
  (sagittarius (import (sagittarius)))
  (chibi (import (chibi)))
  (else (error "sorry")))

(define-syntax my-let
  (er-macro-transformer
    (lambda (form rename compare)
      ;; form = (let bindings body ...)
      ;; bindings = ((var val) ...)
      (let ((bindings (cadr form))
            (body (cddr form)))
 `((,(rename 'lambda) ,(map car bindings) ,@body)
   ,@(map cadr bindings))))))
ER展開器は3つの引数を取る手続きを受取りマクロ展開器を返す。それぞれ入力式、リネーム手続、比較手続の3つである。ERで最も重要なのは二つめのリネーム手続で、この手続きによってマクロの健全性を保証することができる。上記の例ではマクロ内でlambdaをリネームすることによって、以下のような場合でも正く動作することを保証することができる。
(let ((lambda 'boo))
  (my-let ((a 1) (b 2)) (+ a b)))
;; -> 3
ERでは健全性、入力式のチェック等は全てユーザに委ねられる。syntax-caseと異りデフォルト(リネーム手続きを呼ばない単なる式変形)では非健全である。

どうやって動いてるの?

ERの動作原理は実に単純である。リネーム手続きはシンボルをマクロ定義時の環境から見える識別子にして返す。例えば上記の例ではmy-letが定義された際に見える識別子というのは(scheme base)からエクスポートされているものになる。これはlambdaを含むのでリネーム手続きにシンボルlambdaを渡すと(scheme base)からエクスポートされているlambdaを指す識別子を返してくる。
;; very naive/simple image

;; environment when my-let is bound
;; ((exporting-name . actual-binding-name) ...)
'((lambda . |lambda@(scheme base)|)
  ... ;; so on
  )

;; very naive implementation of rename procedure
(define (rename s)
  ;; (macro-environment) returns the above environment
  (cond ((assq s (macro-environment)) => cdr)
        (else
   ;; convert to identifier which is bound in macro-environment
   #;(implementation-dependent-procedure s)
   )))
ここではリネーム手続きはシンボルのみを受け取ると仮定しているが、処理系によってはフォームを受け取ることも可能である。特に仕様が決っていないので処理系独自に拡張されているが、ERをサポートしている多くの処理系ではフォームを受け取ることが可能である。

追記:
リネーム手続きに同名のシンボル又は識別子を渡すと常に同一の識別子が返って来る。同一のオブジェクト(eq?で比較した際に#t)ではない可能性に注意してほしい。R6RSの語彙を借ればbound-identifier=?#tを返す識別子である。
(define-syntax foo
  (er-macro-transformer
    (lambda (form rename compare)
      (list (rename 'a) (rename 'a)))))
(foo)
;; -> list of the same identifiers in sense of bound-identifier=?

(let () (foo))
;; -> list of the same identifiers as above macro expansion
;;    because input of rename is always 'a
「Hygienic Macros Through Explicit Renaming」によればリネーム手続きの呼出毎にeqv?#tを返す識別子が新に作られるが、多くのR7RS処理系(Gauche、Chibi、Sagittarius)では同一のオブジェクトを返すようになっている。もちろんそれに依存したコードを書くと後で痛い目にあうかもしれない。

比較手続き

ERが受け取る3つ目の手続きは比較用手続きは渡された2つの入力式が同一であるかを比較する。ここでいう同一とは、同一の束縛を指す。言葉で説明するよりも例を見た方が早いので先ずは例を見てみよう。
(define-syntax bar (syntax-rules ()))
(define-syntax foo
  (er-macro-transformer
    (lambda (form rename compare)
      (define (print . args) (for-each display args) (newline))
      (print (compare (cadr form) (rename 'bar))))))

(foo bar)
;; -> #t

(foo foo)
;; -> #f

(let ((bar 1))
  (foo bar))
;; -> #f
barは束縛されている必要はないのだが(なければ未束縛として比較される)、ここでは話を簡単にするために敢えて束縛を作っている。fooは一つ目のフォームとリネームされたbarが同一の束縛を指すかをチェックするだけのマクロである。 
一つ目の(foo bar)では与えられたbarは大域に束縛されたbarと同一の束縛を指すので#tが返る。これは以下のようにした際に参照される束縛と同一のものと考えれば自明である。
bar
;; -> syntax error
二つ目の(foo foo)barではないので#fが返る。
三つ目の(foo bar)は引数barがマクロ展開時に見える束縛と異る為に、この場合は局所変数barが見える、#fを返す。
R6RSの語彙を借て説明すれば、比較手続きはfree-identifier=?とほぼ同義である。(処理系の拡張によってフォームを受け取れる可能性があるため「ほぼ」としている。)
比較手続きを用いることでcondelseなどの補助構文の導入が可能になる。

まとめ

非常に簡潔にだがERの使い方及び動作モデルの説明をした。syntax-caseでもそうだが、ERも付き詰めればマクロ定義時と展開時の識別子が何を指すのかというところに落ち着き、ERではこれを非常に明示的に記述することができる。

参照

William D Clinger - Hygienic Macros Through Explicit Renaming
https://groups.csail.mit.edu/mac/ftpdir/users/cph/macros/exrename.ps.gz

2015-10-24

er-macro-transformer on top of syntax-case

There are numbers of low level hygienic macros in Scheme world. The most famous ones are probably the followings:
  • explicit renaming
  • syntax-case
  • syntactic closure
Of course there are more (e.g. ir, reverse syntactic) but if you discuss low level hygienic macros, then above would usual be the ones.

R6RS has syntax-case and rumour says R7RS would have explicit renaming. According to this article, if implementations have one of them, then the rest can be implemented atop it. I'm wondering is it really true? Very lame conclusion is true. Because Sagittarius uses kind of syntactic closure and implements both explicit renaming and syntax-case. Now, can it be done in a portable way?

So I've wrote this. It seems this can work most of R6RS implementations except Racket. Though I haven't tested on Larceny, Guile and Vicare yet, they are using either Psyntax or van Tonder expander such as Mosh and IronScheme (Psyntax) or NMosh (van Tonder). So should work.

The basic idea of the implementation is very simple. rename procedure is a simple wrapper of datum->syntax. compare is free-identifier=?. Then wrap the returning form with datum->syntax*.

The initial revision of the Gist used mere datum->syntax. This wasn't good enough because the procedure should only accept datum not syntax object. The error was raised by Psyntax implementations and Racket. Then I've been suggested to walk thought the returning form.

I first thought this won't work because traversing and constructing a new form would return a list not a syntax object. However I was just didn't consider thoroughly. If I use syntax-case and quasisyntax (with-syntax could also be), then I can construct syntax object containing syntax object renamed by er-macro-transformer. So I've rewrite the code. Then most of the R6RS implementation seem working. Even Racket seems working if the macro is very simple like the one on the comment.

Now, my question is 'Is this R6RS portable?'. R6RS standard libraries 12.2 says:
The distinction between the terms “syntax object” and “wrapped syntax object” is important. For example, when invoked by the expander, a transformer (section 12.3) must accept a wrapped syntax object but may return any syntax object, including an unwrapped syntax object.
So transformer *MAY* return unwrapped syntax object. Though what I'm doing is returning wrapped syntax object so should be fine. What I couldn't read is whether or not a syntax object can contain syntax object(s) inserted by other transformer. If this is required feature, then this might be a bug of Racket. Otherwise this is not portable.

I hope it's a bug of Racket, then you (not me) can write an explicit renaming SRFI with sample implementation.

For convenience, embedded source.

2015-10-18

カスタムポートとソケットとバッファポート

「と」で繋げるとなんとなくアニメとかのタイトルっぽい感じがするなぁ。

Sagittariusは0.6.9でポート周りにかなりバグを混入した(弄った)のだが、頭を悩ませるバグが顕在化した。それが表題のポートである。どこで使われているかといえばTLSである。

何が問題か?いくつかの問題が合わさってるのではあるんだが、一つはget-bytevector-nとカスタムポートの相性。カスタムポートは要求されたバイト(文字数)を返す必要はないので、例えば1バイトずつ返して呼び出し元に判断させるということができる。例えば以下のようなの
(import (rnrs))

(let* ([pos 0]
       [p (make-custom-binary-input-port
           "custom in"
           (lambda (bv start count)
             (if (= pos 16)
                 0
                 (begin
                   (set! pos (+ 1 pos))
                   (bytevector-u8-set! bv start pos)
                   1)))
           (lambda () pos)
           (lambda (p) (set! pos p))
           (lambda () 'ok))])
  (get-bytevector-n p 3))
;;-> #vu8(1 2 3)
R6RSテストスイーツからの抜粋なのだが、read!手続きは1バイトずつ処理しget-bytevector-nが最終的に何を返すか決定するという形である。カスタムポートが扱うのが有限のデータなら特に問題ないのだが、ソケットのようにいつEOFがくるか分からないものだと割と困るのである。例えばread!の部分がrecvを使っていたとして、あるソケットは要求の半分のデータを受信したする。そうするとget-bytevector-nは残りの半分を取得するためにもう一回read!を呼び、処理はブロックされる。

不定長のデータを扱うのにget-bytevector-nなんて使うなという話なのだが、本当の問題は別のところにある。0.6.9からバッファポートを導入したのだが、こいつとカスタムポートの相性が悪い。何が悪いかと言えば、バッファを埋めるのにget-bytevector-n相当のことがされているのである。カスタムポートを実装したときに、あまり何も考えずにポート側でバイト数を数えるようにしてしまったので複数回の呼び出しが起きるという話なのではある。

解決方法は多分2つくらいあって、
  1. バッファを埋める処理を別枠にする
  2. 現状ポート側でやってることをget-bytevector-nに移す
1.はそこそこadhocな感じがして嫌だなぁ。2.は(99.99%ないけど)別のところに影響が出る可能性がある(もしくは考慮漏れによるバグの混入)。でも2かなぁ、どう考えても。それでとりあえずはバッファの問題は解決するし。

2015-10-15

CPSマクロ

assocをマクロで書いたらどうなるか、ということを考えた。これくらいならそんなに難しい話ではなく、以下のように書けるだろう。
(import (scheme base) (scheme write))

(define-syntax assocm
  (syntax-rules ()
    ((_ key (alist ...))
     (letrec-syntax ((foo (syntax-rules (key)
                            ((_ (key . e) res (... ...)) (key . e))
                            ((_ (a . d) res (... ...)) (foo res (... ...))))))
       (foo alist ...)))))

;; a bit of trick to avoid unbound variable
(define (c d) (list 'c d))
(define d 1)

(assocm c ((a b) (b d) (c d) (d d)))
;; -> (c 1)
取り出せるのであれば、その中身も欲しい。つまり、carcdrだ。これも同じ要領でやればこんな感じで書けるだろう。
(define-syntax cdrm
  (syntax-rules ()
    ((_ (a . d)) d)))

(cdrm (c . d))
;; -> 1
だが、これら二つのマクロはこんな感じでは組み合わせられない。
(cdrm (assocm c ((a b) (b d) (c d) (d d))))
;; -> error
これはcdrmassocmより先に展開されるからである。あるマクロの展開結果を別のマクロで使いたい状況というのはしばしばある。そういうときにはCPSでマクロを書く。最初のassocmをCPSで書いてみよう。
(define-syntax assocm/cps
  (syntax-rules ()
    ((_ k key (alist ...))
     (letrec-syntax ((foo (syntax-rules (key)
                            ((_ (key . e) res (... ...)) (k (key . e)))
                            ((_ (a . d) res (... ...)) (foo res (... ...))))))
       (foo alist ...)))))

(assocm/cps cdrm c ((a . b) (b . d) (c . d) (d . d)))
;; -> 1
このassocm/cpsは最初の引数に次に展開するマクロを受け取ることで、マクロの展開が終わった際に展開結果(この場合は(key . e))を引数kに渡すことを可能としている。要するに単なるCPSであるがこの状態では割と致命的な欠点がある。それは複数のマクロを組み合わせることができないということである。

例えば上記の例でcadrmはどう書くだろうか?普通に考えれば、carmを定義したのち、cdrmを組み合わせて書きたいところであろう。(もちろんゴリゴリ書いてもいいんだけど。) そう(compose f g)みたいなことがしたわけである。
;; I want to write like this!
(assocm/cps (composem cdrm/cps carm) c ((a . b) (b . d) (c . d) (d . d)))
こうなると、単にマクロを受け取って結果を渡すだけではなく、次のマクロが複合マクロかどうかを判別して上手いことやってくれる何かがほしい。こんな感じだろう。
(define-syntax composem (syntax-rules ()))

;; assume k is CPS macro
(define-syntax extract/cps
  ;; it's a bit awkward to have own name in literals
  ;; but this saves me a lot
  (syntax-rules (composem extract/cps)
    ((_ (composem k) args ...) (k args ...))
    ((_ (composem k ...) args ...)
     (extract/cps "flatten" () (k ...) (args ...)))
    ;; flatten nested composem
    ((_ "flatten" (cps ...) ((composem k ...) k* ...) args)
     (extract/cps "flatten" (cps ... k ...) (k* ...) args))
    ((_ "flatten" (cps ...) (k k* ...) args)
     (extract/cps "flatten" (cps ... k) (k* ...) args))
    ((_ "flatten" (cps ...) () (args ...))
     (extract/cps (extract/cps cps ...) args ...))
    ;; extract/cps keyword
    ((_ (extract/cps (composem k)) args ...) (k args ...))
    ((_ (extract/cps (composem k k* ...)) args ...)
     (k (extract/cps (composem k* ...)) args ...))

    ((_ (extract/cps k) args ...) (k args ...))
    ((_ (extract/cps k k* ...) args ...)
     (k (extract/cps (composem k* ...)) args ...))
    ;; short cut
    ((_ k args ...) (k args ...))))
多少無理やり感があるので(extract/cpsリテラルとか)もう少し綺麗にならないかと思ったりはするのだが、まぁとりあえずこんな感じでいいだろう。これを使って上記のassocm/cpsは以下のように書き換える。
(define-syntax assocm/cps
  (syntax-rules ()
    ((_ k key (alist ...))
     (letrec-syntax ((foo (syntax-rules (key)
                            ((_ (key . e) res (... ...)) 
                             (extract/cps k (key . e)))
                            ((_ (a . d) res (... ...)) (foo res (... ...))))))
       (foo alist ...)))))
さらにcarm/cpscdrm/cpsをこんな感じで定義して、最後のkvaluesmとして定義しよう。CPSマクロの最後に展開されるマクロはCPSではないことに注意しよう。
(define-syntax cdrm/cps
  (syntax-rules ()
    ((_ k (a . d)) (extract/cps k d))))

(define-syntax carm/cps
  (syntax-rules ()
    ((_ k (a . d)) (extract/cps k a))))

(define-syntax valuesm
  (syntax-rules ()
    ((_ args) args)
    ;; this isn't really values...
    ((_ args ...) (args ...))))
こうするとassocmから見つかった値のcadr部分をとるマクロは以下のように書ける。
(assocm/cps (composem cdrm/cps carm/cps valuesm) c ((a b) (b d) (c d) (d d)))
;; -> 1
ちなみに、このコードGaucheでは(まだ)動かないので(すぐ直されると思うけど)、実際に動かしてみたい場合はSagittarius、Chibi、Larcenyのいずれかを使うといいだろう。

ちなみに、この手のコードは3日もすると自分でも理解不能になる危険を孕んでいるので使用する際は十分に留意した方がいいだろう。こういったマクロはだいたOleg氏がまとめているので、メタプログラミングの深淵を覗きたい方はそちらを参照されたい。この辺とか。

2015-10-12

Small Scheme or large Scheme?

2 topics about the size of Scheme were posted on c.l.s. One was rather branch of other topic:How many R6RS users and how much code out there?. And the other is indirectly suggesting it: Question about vote of RnRS (the poster mentioned about the change between R5RS and R6RS as drastic change so seems it's about the size.) Even though all what I wanted to say is already said by Taylan on the first topic I've mentioned, I want to write something about the size so bare with me :)

The point of this topic for me is the definition of small or large. The poster said it is useful enough for educational purpose. I agree with it. If I need to add a bit of my opinion about this, I would say the languages which has proper design for the topic of the class are useful enough for educational purpose as long as students don't use convenient libraries. Java is fine for OOP, C++ is fine for OOP and meta programming, Mathematica is excellent for math, etc. So they can also be programming languages for educational purpose, right? Now are they small?

The answer for me is no. Especially if you see C++'s specification, it's more than gigantic even human beings couldn't understand, IMHO (are there people who understand all the spec?). I wouldn't say it's one of beautifully designed language, but it's powerful enough to cover other purposes including professional use . Then, should Scheme be this much huge to make all programmer happy?

My answer is again no. It's too complicated, it's piling up features on top of other features on top of other, lemme quit. One of the reason why C++ is piling up those features, I believe, is that it doesn't have enough abstraction to make language self growing. Most of programming language don't have this type of feature such as defining new syntax. Or if they have it, it'd be rather complicated to use, either deliberately or accidentally. If it's deliberately, then the designer of the language doesn't want users to use it casually. If it's accidentally, then it's not considered well but made rather adhoc. The first decision is understandable, sometimes those things are not really needed and don't want users to summon daemons from their nose.

Now what's the definition of small in Scheme specification? In my opinion, there is no need to pile up features but it can grow by itself. Let me elaborate what it means.  Currently there're on going discussion about hashtable on SRFI. This might be a good example to do it. Is hashtable required by small language as Scheme? Well, my answer from bottom of my heart is yes but rational answer is no. Why no? It can be implemented by vector and record. Now one of the SRFIs also mentioning weak hashtable. This is rather interesting. Implementing this data structure can not be done neither in range of R6RS nor R7RS. So this seems required, right? Wait a sec, there's a draft SRFI about ephemeron. If you use this, then you can implement weak hashtable using vector, record and ephemeron. So the absolute requirement to have is this one. Hurrah, the language spec is kept small enough!

IMO, this is a bit too extreme. Each time users need to make own utility libraries for those common data structure is ridiculous. Then here comes R7RS-large process. The purpose, in my understanding, of this process is that keeping core language absolutely minimum and put a collection of those commonly used things in its specification. So implementations may or may not support all of them. Oops, again, what's absolutely minimum?

Unfortunately, I don't have generic answer for this and, I believe, neither most of Schemers do. The only thing I do have now is that it's not enought to be perfect language which can solve all problems in this world. Concurrency, networking, weak data, etc. These are not in the specification (maybe yet) but absolutely needed. If there's something lacking, then language specification should grow even if it's got bigger.

The world of computer is growing like speed of light. Problems to be solved are zillion. Too small wouldn't solve. We need small enough.

2015-10-09

bound or free identifier

I've just fixed the bug of incorrect usage of free-identifier=? during macro expansion. As my memo and maybe good to share what I've learnt.

Firstly, have a look at this piece of code:
(import (rnrs))

(define-syntax foo
  (lambda (x)
    (syntax-case x ()
      ((_ (t1 t2))
       ;; what should be print?
       (begin (display (free-identifier=? #'t1 #'t2)) (newline)
              (display (bound-identifier=? #'t1 #'t2)) (newline))
       #''ok)
      ((_ (t* ...) a b ...)
       #'(foo (t* ... t) b ...))
      ((_ a ...)
       #'(foo () a ...)))))
(foo 1 2)
If you can immediately see what's printed, then you can skip the next paragraph :)

The difference between bound-identifier=? and free-identifier=? is that the first one only sees where the given 2 identifiers were  created and the second one sees the actual bindings are the same or not. In the above example, identifier ts are created in different places, more precisely different macro expansion process. If you expand the macro manually, then it would look like this:
(foo 1 2)
;; -> (foo () 1 2))
;; -> (foo (t) 2)) ;; <- where the first t is created 
;; -> (foo (t t))  ;; <- the second one is created here in the different macro expansion
;; 'ok
If 2 identifiers whose names are same are created in different macro expansion, then comparing bound-identifier=? should return #f.free-identifier=?, on the other hand, should return #t because those identifiers are not bound to anything thus they have the same binding (unbound variable) and also have the same name (t). (This is what I understood the behaviour of those 2 procedures. Correct me, if I'm wrong.)

Now the bug was related to this difference. The detail is here. In the description, it says free-identifier=? returns #t against pattern variables t but this is correct behaviour. What I did wrong was using free-identifier=? to compare pattern variables during expanding template variables. Moreover, compiler for syntax-case renamed pattern variables which must be preserved so that expander can use bound-identifier=? to compare pattern variables.

If I know what's wrong, then fixing it is not a big problem. Just adding extra check for pattern variable and use bound-identifier=?. Done! I hope this would be the last article related to macro bug... (feeling won't though)

2015-10-08

マクロバグ

何回目だろうこのネタ。もういい加減尽きたと信じたかったが、そうもいかないらしい。

バグの報告は以下のツイート
突き詰めていくと、テンプレート変数を割り当てていく部分で使用しているfree-identifier=?がこの条件だと全ての一時パターン変数に対して#tを返すということが分かった。adhocに直すならこういう場合の比較に対しては#fを返すようにすればいいのだが、コードを眺めていてふと思った、「こいつらbound-identifier=?で比較しないとまずくね?」と。

単純にこの二つの手続きを置き換えるだけなら何の問題もなく、こんな記事も書いてはいないのだが、そうは問屋が卸してくれなかった。問題になるのは、with-syntax等でラップされた式の中で束縛されたテンプレートを返すようにした場合である。例えばこんなの:
(syntax-case x ()
  ((_ (k ...))
   (with-syntax (((e ...) (gen)))
     #'(lambda (x) (syntax-case x (k...) e ...)))))
具体的にはsyntax-rulesがこんな感じの定義なんだけど、パターン変数がそのままマクロによって生成されるsyntax-caseで使われているのがまずい。現状の実装ではマクロの展開が走ると問答無用で識別子がリネームされてしまうので、パターンのkとテンプレートのkが別の識別子として束縛されてしまう(つまりbound-identifier=?#fを返す)。

あれ、待てよ。パターン変数として束縛された識別子はマクロ環境で束縛されているので、リネームの際にそれを避けるようにすれば無用なリネームが発生しないことになるな。その方向でいくか。やはり問題は一度書き出すとなんとなく解決策がでてくるものだな。まだ解決してないけど。

2015-10-07

Timezone related bugs

Since Sagittarius 0.6.7, it has timezone object. The rationale behind this is pretty simple. Before it used localtime and some other C APIs to get proper local timezone offset. I wasn't unhappy until I needed to handle other timezone offsets. I don't remember exact situation but related to time conversion. Unfortunately, on POSIX there is no way to treat timezone as objects (as far as I could research), so I've decided to implement own timezone handling.

Timezone is related to physical location. Of course, you can change your computer's setting to deceive yourself. I wasn't one of those people and that bit me. I've faced 2 timezone related bugs. Both could only happen in particular places, Japan and country where no summer time. Let me share the bug story. Starting from the first one.

There is IANA TZ database and I'm using it to find proper timezone offset. If you build Sagittarius from repository, then the pre-build process, not cmake but dist.sh, downloads TZ database and compiles it to S-expression. It's not too bad. The only bad thing is that it can't handle any rules not written in the TZ database, such as Japan.

Asia/Tokyo timezone has rather weird rules. According to the TZ database, Japan had summer time between 1948-1951. On the comment, it clearly says this is used only on US military base, for your information, so officially Japan didn't have it, though. Funny thing is that this rule, named Japan, is associated to Asia/Tokyo timezone and it's active now (2015 current). Additionally, the rule doesn't have definition of after 1951. So what should happen? Maybe I didn't read all the comment or how the rules defined properly so I missed something. Anyway, the previous behaviour of handling this situation was signaling an error. Which, of course, caused problem. The biggest one was Sagittarius couldn't be built in Japan.

Thanks to the comment on this blog, I could notice there was such a problem. Other than that, this would stay until I'd decide to go back to Japan. The fix was rather simple, instead of signaling an error, it simply returns default timezone offset without considering old timezone offset. I think that's good enough. (NB: the timezone object would consider the when, means if you ask timezone offset of before 1835 in the Netherlands, then it would return GMT+0:19:32. No need for this? just for fun.)

The second one was rather stupid mistake. Again it was in Japan. I've found a tweet that said time-utc->date didn't consider timezone offset but just return UTC. I saw this when I fixed the first bug so I thought it might be related. Well, kinda but not quite. This bug happened only on Windows (including Cygwin) running on a timezone without summer time (Japan for example).

The reproducing was one easy step. Change system timezone to 'Osaka, Sapporo, Tokyo' then get local timezone. Aha, it returned UTC. But why? Well, very simple. To get local timezone name on Windows (and Cygwin), Sagittarius uses GetTimeZoneInformation and check the return code. If the return code was not TIME_ZONE_ID_UNKNOWN then it returns standard timezone name, otherwise UTC. Hey, MSDN says if the timezone doesn't have summer time then this return code would be returned! That's why if it's in Japan, it returned always UTC. Careless (or stupid) mistake.

Even though I'm using CI services for Linux, Windows and OS X, this type of physical location related bugs are really hard to find. (Not even sure if I can change system timezone per build on the services) I've just seen importance of feedback in a fresh light.

08 Oct 2015
typo fix. the light wasn't from jewel meat...

2015-09-29

暗号ライブラリ (別題:実用Scheme)

Schemeは黒板言語だと言われたりするのだが(概ね認める部分もあるが)、プログラミング言語は実用されないことにはコミュニティも広がらないだろうということで、完全R7RSのみで暗号ライブラリを作っていたりする。ちなみにR6RS処理系用はindustriaがあるので、そっちを使った方がよいと思われる。

ライブラリの名前はAeolus(アイオロス)。まぁ、そういうことです。基本的にはSagittariusで実装されてる(crypto)ライブラリに似せた感じのAPIにしてある。使い方は大体こんな感じ。
(import (scheme base)
        (aeolus cipher)
        (aeolus cipher aes)
        (aeolus modes ecb))

;; 128bit key
(define key (string->utf8 "1234567890123456"))
(define cipher (make-cipher AES key mode-ecb))

;; 16 octet block
(cipher-encrypt cipher (string->utf8 "It's top secret!"))
;; -> #vu8(230 1 210 64 10 131 72 18 222 112 210 129 170 236 243 42)
パディングとかはまだ実装してないので、自前でデータをブロック長にする必要があったりする。

以下はここにあるR7RS準拠の処理系での動作チェック。部分準拠のものは試してない。

完動(全テストパス)
  • Sagittarius 0.6.8
  • Gauche 0.9.5 (HEAD)
  • Larceny 0.98 (ただしパラメタのテストはtest-errorの実装がおかしいので動かない)
  • Chibi Scheme (23ac772e3a)
テスト失敗
  • Chibi Scheme 0.7.3 (AESのテストがこける。SRFI-33っぽい、使わないようにしたらテスト通った)
動かん
  • Foment (複数のバグを踏んだ)
  • Picrin (パスの通し方が分からん)
  • Kawa (同上)
未検証
  • Husk (Haskellいれるのだるい)
PicrinとKawaはなんとか試してみたいのだが、いかんせんライブラリパスの通し方が分からんので手が出せない。誰かテストしてくれないかな(チラ その他リストには載ってないけど動いたとかの報告があると嬉しいなぁ(チラ

とりあえずDES、Triple DESとAESをサポート(というか、当面はこれだけの予定。Blowfishとか欲しい人いる?) 以下は当面のTODO
  • パディング(パラメタにするか明示的にユーザにやらせるか悩み中)
  • ハッシュ(MD5、SHA-1、SHA-256、SHA-512等)
  • MAC(HMAC、CMAC辺り)
  • RSA
  • PKI(X.509証明書とか。ここまでやるとほぼSagittariusの焼き増しに・・・)
 これくらいあるとTLSとかSSHとか実装できそう。

なんでこんなの作ったのか?


上の方に書いたのと被るけど、○○がないからSchemeは使わない(使えない)と言われるのが嫌だったから。仕様内だとソケットやスレッドがないのでいろいろ厳しいんだけど、そこに依存しないピュアSchemeなライブラリを書いていけばそのうち人が増えるのではないかと。黒板言語と呼ばれる理由の一つに実用的なライブラリが圧倒的に足りないというのがあると思うので、そこを何とかしていけばいつかきっととか。以前書いたPostgreSQLバインディングもそんな気持ちからというのはある。(Scheme使ってPostgreSQL使ってるっていう人の方は少ない気がするので、ちとニッチ過ぎたというのはあるが・・・)

まぁ、後は仕事で暗号関係を使わなくなってきたので、忘れないようにというのもある。誰にも聞かれないと思うけど、一応動機。

2015年9月30日追記
Chibiのバグが直されたので完動に追加。仕事が速い。

2015-09-24

process-wait with timeout argument

Recently, I'm writing own CI task on my local machine. (it doesn't mean I quit others when it's completed but just for fun.) Then, I've noticed that it might be convenient to have timeout argument on process-wait instead of using timer to poll every 500 ms (or whatever). So I've implemented it, now you can use like this:
(import (rnrs) (sagittarius process))

(let ((p (call "sh" "sleep_forever.sh")))
  ;; wait for 5 seconds. can also be time object.
  (unless (process-wait p :timeout 5))
    ;; it returns #f if timed out. so kill it
    (process-kill p)))
Now, I don't have to make timer to check. Very convenient :)

TL;DR


From here is the description of underlying implementation. This is not something you may be interested in but simply for my memo (and hope that somebody would indicate better solusion).

Sagittarius supports both Windows and POSIX environment. On Windows, the story was very simple, I just needed to call WaitForSingleObject with process handle and timeout millisecond. Hurray done!. I like this abstraction that API can handle almost any kind of handle. (Most of the time it's a headache to support Windows but sometimes it's easier than POSIX.)

On POSIX, on the other hand, it doesn't have timedwaitpid or something like that. I've asked the teacher, Google, what would be the solution. The first hit was this: Waitpid equivalent with timeout?. Its best answer doesn't seem the best answer since entire process would be affected. Plus, it would always wait for specified timeout amount of time which is not something I want. The most useful pointed one looks nice if POSIX has a portable way to get standard output file descriptor from pid. Though, there seems a way to do it using ptrace(2). (See reptyr(1) and  its source). I haven't looked into its detail but, in my understanding, it opens given pid process with ptrace(2) and calls dup(2) on that process (ptrace_remote_syscall does this black magic I think). It'd be nice to have it if I can do this all platforms Sagittarius supports. However not an easy task to do it without having real environments (e.g. OS X is only on Travis CI).

Go easy


What I wanted to do is waitpid with timeout. So I just need to have a watch dog which alerts either timeout is happened or the target process is finished. Well, the easiest one I could think of was thread with pthread_cond_timedwait(2).

The idea is pretty much simple. It goes the following steps:
  1. Create a thread with the thread entry which calls waitpid
  2. Call pthread_cond_timedwait.
    1. If this return ETIMEDOUT, then send signal to the thread and return #f
    2. Otherwise return the return code.
Done! What an easy solution! (There was a stupid mistake. I didn't know pthread_join can't be called with detached thread. Though, interestingly, it worked on FreeBSD, why?)


Issue


Well, if I can say this is a perfect solution, I'd be super happy but of cource this has an issue (for now only one I'm facing!). Because of the limitation of waitpid (2), the pid can be waited must be created by the parent process means Sagittarius script. Thus processes created by pid->process can't be passed (well this is not only for timeout argument but entire procedure issue, though). If this happens, then ECHILD is raised (see waitpid(2)).

I haven't got any problem with it but if would, then I need a better solution (maybe set PPID to running process? but how?). But for now, I'm happy enough and I believe there's very few situation which users want to wait non child processes.

Again, this isn't an issue on Windows. I don't care good or not but I like it.

2015-09-22

SMTPクライアント

何かが失敗したときにメールを飛ばせると便利かなぁと思い書いた。こんな感じでメールが飛ばせる(サンプルはドキュメントから)。

(import (rnrs) (rfc client))

;; creates SMTP mail object
(define mail 
  (smtp:mail
   (smtp:from "Your name" "your-address@example.com")
   (smtp:subject "Subject")
   "Message"
   (smtp:to "recipient@example.com")))

;; creates an SMTP connection
(define smtp-conn (make-smtp-connection "your.smtp.server.com" "587"))

;; connect to the server
(smtp-connect! smtp-conn) ;; returns SMTP connection

;; Authenticate if required.
(when (smtp-authentication-required? smtp-conn)
  ;; NOTE: only AUTH PLAIN is supported for now
  (cond ((memq 'PLAIN (smtp-connection-authentication-methods smtp-conn))
         (smtp-authenticate! smtp-conn (smtp-plain-authentication
                                        "username"
                                        "password")))
        (else (smtp-disconnect! smtp-conn)
              (error #f "authentication method not supported" 
                     (smtp-connection-authentication-methods smtp-conn)))))

;; Send it
(smtp-send! smtp-conn mail) ;; returns SMTP connection

;; Clean up
(smtp-disconnect! smtp-conn)
メールを作る部分は利便性を高めるためにマクロを用意してて、これの嬉しい点としては、記述力が高いこともあるけど、以下のようにメールをテンプレートとして外部ファイルに書き出しておいて、readevalで手軽に作成することができることもある。
(define mail
  (eval (call-with-input-file "mail.scm" read)
        (environment '(rnrs) '(rfc smtp))))
今のところは考えてないけど、メールのソース(MIMEテキスト)からメールをパース・生成するというのがあってもいいかもしれない。(その前に認証をもう少しなんとかしないとという感じではあるのだが。PLAINだけとかいくらなんでもねぇ・・・)

 一応RFC5321に書いてあるコマンドは全部実装してあるが、拡張とかは全然だし、エラー処理とかもまだ大分甘いので使って直していくという感じ。

2015-09-11

call/ccで嵌った話

call/ccというよりはguardなんだけど。

エラー処理をしたいとか、エラーが起きても処理を継続したいという場合はままある。そういったときに使えるのはguardであることもまぁ周知の事実だと思う。これから提示する例も常識的に理解されているものかもしれない。

まずは以下の例を見てもらいたい。
(import (rnrs))
;; (import (scheme base) (scheme write))
;; (define mod modulo)

(define count 100000)

(define (run)
  (let loop ((i 0))
    (if (= i count)
        i
        (guard (e (else (loop (+ i 1))))
          (when (zero? (mod i 5))
            (error 'who "dummy"))
          (loop (+ i 1))))))

(display (run)) (newline)
(flush-output-port (current-output-port))
これをみて、「あぁ、これはまずいわ」と一目で分かったら以下を読む必要はないです。

これがまずいプログラムだということは既に書いているのでいいとして、何がまずいか。問題になるのはguard内で外側のloopを呼んでいること。一見すると問題ないように見えるのだが、多くの処理系でguardの実装にcall/ccを使用しているのが問題になる。実装例:SRFI-34
参照実装を展開して簡潔に書くと以下のようになる。
(define (run)
  (let loop ((i 0))
    (if (= i count)
        i
        ((call/cc (lambda (k)
                    (let-values ((args (loop (+ i 1))))
                      (k (lambda () (apply values args))))))))))
はい、末尾再帰じゃないですね。なのでスタックがあふれます・・・orz

実際のところとして、R6RS的には末尾再帰になることを要求しているので上記はスタックがあふれるとまずいのだが、(嘘ついた。<cond>を<body>と空目した。)これが問題なく動いたのは確認した中ではChezとRacketだけ。(GuileとVicareは試してない。) もちろん、この2つはスタックを拡張して動かしてるだけかもしれないけど・・・ちなみにR7RSは末尾再帰であることを要求していないので、上記は動かなくても問題ない。

この挙動で嵌ったの実は2回目で、3度目があると嫌だなぁと思ったので適当に書き記しておく。 しかし、どうやったら末尾再帰なguardが実装できるんだろう?参照実装では無理だよなぁ?

追記:
直した。https://bitbucket.org/ktakashi/sagittarius-scheme/commits/7bab13c1e83820eda28fc7878b14209fe1b87df3?at=default

追記の追記:
Shiroさんとのやり取りで上記の修正が正しいのか不安になってきた。っが、問題になるケースが思い浮ばない+スタック消費しないのでこのままで行くことにする。

Problem of hop on hop off projects

Hop on hop off projects is the term I made. This means you join a project in short term, then join other project in short term, like hop on hop off tour buses. (I just don't know any word describes such a style of driving project, drifting?)

I'm currently working with kind of scrum environment. Why kinda? It's because sprint period is rather longer than usual (4-5 weeks) and no standup meeting. The same part is that each sprint I get new task(s). By now, the tasks I've got assigned were not really related so each time I need to look into something I don't know (of course product specific thing). Thus hop on hop off projects.

It might be only me but if I don't have long term commitment of a project, then I lose interest and start writing crappy code. This is because I start thinking that "I would move to next something I don't know anyway why should I write maintanable code?". Probably, I don't feel any responsibility to the code I'll never see in future. (Plus, the current code base is really pile of shit, I don't want to swin into that. Too risky...)

What happen if I'm such a state? For example:
  • Start using copy&paste instead of extracting common use-case somewhere usable place.
  • Using magic number/string as everybody is doing.
  • No tests (well, I don't think there's a culture writing a test in this company...)
These are happening right now. Of cource I know I'm not doing right but risk is too high if I touch/refactor something without tests. I do what I suppose to do but I'm not those highly motivated people so I don't much care as long as I don't see it anymore.

The funny thing about this is that my company is actually developing one product however they don't assign to the same project (so far) or don't have long term assignment. Each task must be done at most a month. I understand that's the basic idea of scrum. But by now, I can only see the greate failure, such as:
  • Wrongly abstracted classes
  • No tests
  • Copy&pasted code
  • Only few people know the structure of code/architecture
  • No refactoring (of cource, there's no efficient tests!)
  • etc.
I'm such a lazy person so I'd write as maintanable as possible if I need to maintain the code. But if I don't have to, this laziness seems to take into horribly.
Or maybe I'm considered as one of useless developers so they don't want me to do anything but piling crap. That's fine by me, as long as they pay my salary.

2015-09-09

ハッシュテーブルSRFIs

ハッシュテーブルに関するSRFIが2つ提出された。一つはJohn Cowanの「SRFI-124: Intermediate hash tables」でこれは既存のSRFI-69の互換性を保ちつつ拡張するというもの。もう一つはTaylan Ulrich Bayırlı/Kammerの「SRFI-126: R6RS-based hashtables」でこれは名前からも分かるようにR6RSで標準化されたハッシュテーブルを拡張するもの。SRFI-126はweakハッシュテーブルを要求しているのでこちらを実装すればもう片方は実装可能という感じである。(bimapをどうするかとかはあるが、Schemeで実装してしまえばいいわけだし、気にしないことにする。所詮別の型だし。)

これだけなら特にネタにもならないのだが、現状SRFI-126はweakハッシュテーブルと通常のハッシュテーブルの操作を同一の手続きで行えることを要求している。インターフェースの統一という感じだし、実用を考えればわざわざ「weak-hashtable-ref」とか書かずに「hashtable-ref」でアクセスできた方が楽というのはあるだろう。問題はどうこれを実現するかということだ。普通に全ての手続きでハッシュテーブルのタイプを場合分けしてもいいんだけど、泥臭い上に拡張性が低い。別のハッシュテーブルが追加されるという可能性は低いといえば低いが、ないわけでもないだろう(concurrentハッシュテーブルとか)。とすると、もう少しマシな方法を考える必要がある。

現状Sagittariusはハッシュテーブルとweakハッシュテーブルは完全に別の型としているのだが、これを以下のようにするとなんとなく拡張性が高くなりそうな雰囲気がある(あくまで雰囲気)。
          +-----------+
          | hashtable |
          +-----+-----+
                |
      +----------+-----------+
      |                      |   
+-----+------------+ +-------+--------+
| normal hashtable | | weak hashtable |
+------------------+ +----------------+
まぁ、普通というか、ひねりも何にもなくインターフェースと実装を分けるだけという。実際にはこれにmutableとimmutableのクラスを追加してやろうかなぁとも考えている。こうしておけば後で意味不明なハッシュテーブルが現れてもそれなりに問題なく動くことが期待できそうだ。

このSRFIは出てきてまだ数日なので上記の変更を入れるかを決めるのは時期尚早な気がする。ただ、この変更自体はやってもいいかなぁとも思えるのでどうしようかなぁというところ。

2015-08-28

OS X support and Travis CI

Travis CI doesn't support Bitbucket so I didn't use it until now. I knew there's a way to use it, more precisely, there's a service which synchronises Bitbucket's repository to Github (BitSyncHub). But I didn't use it since there are couple of CI service which support Bitbucket (e.g. drone.io). Now, I've heard that Travis CI supports OSX so I wanted to use it. Using BitSyncHub wasn't difficult at all (so if you want to use Travis CI, it might be worth to consider). Enabling multiple OS support requires dropping a line to their support. No problem. Then I've got the environment, yahoo!!

OS X is, I believe, considered POSIX OS in most of the case. So I was hoping that Sagittarius would work without any change. Well, it didn't. When I write OS specific code, I refer POSIX spec to make sure I'm writing portable code. Was I doing right? I think so because the code worked on FreeBSD without any change which is also considered POSIX compliant OS. The pitfalls of OSX were the followings:
  • sem_timedwait is not implemented (linker error)
  • sem_init is not supported (can be compiled but an error)
  • Passing O_TRUNC to shm_open is an error.
Well, not that much things but pretty much annoying. Especially the first one. I've created a patch to make 0.6.7 be compiled so that CI server can build it.

Long time ago, Sagittarius got a pull request which made it work on OSX. The PR also contains a fix for libffi search path. It requires to specify the path explicitly. Which I think fine as long as you have control of the environment. However on CI server, we don't know until when the version is there. So I've written kind of solution to fine libffi in build process. So now, you can simply build like the following:
$ cmake .
$ make
It does kinda ugly thing internally but it's working so I'm happy with it.

Then I've experienced build failure number of times (including stupid mistake), finally got the successfull build.

Now, I can say Sagittarius supports OSX again.

2015-08-17

プログラミングにおける公私

駄文

高校で物理の教師が担任だったときに「数学に疲れたら国語を勉強して気分転換して、一日10時間勉強する」とか言われた記憶がある。勉強すること自体に疲れるのにどうやって別科目をやって気分転換するんだ?と疑問に思ったことがある。あれから15年ちょっとなんとなくあの教師の言っていたことが分かった気がする(遅い)。

僕の職業はプログラマで趣味(の一つ)もプログラミングである。職場で書くコードは大なり小なり制約があり思い通りに書くことはできない。言語の制約だったり(Java辛い)、積みあがった糞を崩したくないという精神的枷であったり、あんまり深く追求したくないという己の弱さだったりとまぁいろいろだ。例えば今の職場は、ユニットテストを書く習慣があんまりないかつテスト自体を書くのが驚くほど辛いので既存のコードを弄るのが怖いという個人的には致命的な枷があり、コードを書くのが辛いのである。(そんな環境を変えるという選択肢もあるかもしれないが、そこまで会社に思い入れはない+現状を変えたくないのに権力を持った人がいるので戦ってまで変える気もない。給料分だけ働きます状態。)

そんな状況でコードを書いているといろいろとストレスがたまる。特に現状を変えないように無理やりAPIに切り出す作業とか個人的に大分辛い。そうすると趣味で書いてるプログラムで思いっきり変更加えてストレスを発散しているのである。まさに「プログラミングでプログラミングの疲れを取る」という傍から見たら意味不明なことをしているわけだ。

プログラミングの一つの醍醐味として、自分の思ったとおりのプログラムを作ることができる(可能性がある)というのがあると思っていて、それは例えばパズルのピースがぴったりはまるような感覚で上手く抽象化できたとか、本来なら1000行くらい書く必要があるものを100行まで圧縮できたとか(マクロ中毒)、形は違えど思い通りになる感覚がいいのである。個人的にはこれが得られないとストレスになるらしく、どうしようもなくコピペが要るとか、あまりに酷いコードだけどテストがないから直せないとか、仕事で書くコードはそういったものが趣味で書くものより多いみたいである。

自分が書くコードがきれいとか上手いこといっているとは思わないし思えないが、それでも思い通りに書き換えることができる(もちろん動作は変えないで)というのはやはりストレスを発散することができるようである。特に不要なコードをばっさり削ったときの爽快感は一度味わうと止められない。趣味のプログラミングで気分転換をするときは何かしらがごそっと変わっている可能性がある。いいか悪いかは言及しないことにする。

取り留めなく終わり。