Syntax highlighter

2014-09-30

Timer

When I write asynchronous script, sometimes I want to a timer so that I can invoke some procedure periodically or so. So I've looked at POSIX's timer_create and Windows' CreateWaitableTimer. Then found out both needs some special treatment. For example, POSIX timer_create requires signal handling which is lacking on Sagittarius. (Honestly, I've never properly understood how signal masking works...)

So I've wrote sort of mimic code with thread.
(import (rnrs) (srfi :18))

;; simple timer
(define-record-type ( make-timer timer?)
  (fields (immutable thread timer-thread))
  (protocol (lambda (p)
              (lambda (interval thunk)
                (p (make-thread 
                    (lambda ()
                      (let loop ()
                        (thread-sleep! interval)
                        (thunk)
                        (loop)))))))))

(define (timer-start! timer) (thread-start! (timer-thread timer)) timer)
(define (timer-cancel! timer) (thread-terminate! (timer-thread timer)))

;; use it
(define t (timer-start! (make-timer 2 (lambda () (print "It's time!!")))))

(define (heavy-to-do)
  (thread-sleep! 5)
  (print "It was heavy!"))
(heavy-to-do)
Above prints It's time!! twice then finish heavy-to-do. Now I'm wondering if this is enough or not. Without deep consideration, I've got couple of pros and cons with this implementation.

[Pros]
  • Easy to implement and could be portable.
  • Asynchronous.
[Cons]
  • Could be expensive. (Making thread is not cheap on Sagittarius)
  • Timer can't change parameters which is thread local.
I think above points are more like how we want it to be but it seems better that timer runs the same thread for me. Now, look at both Windows and POSIX timer APIs. Seems both can take callback function. However on POSIX, if I use SIGEV_THREAD then it would create a new thread (it only says "as if" so may not). And not sure if Sagittarius can call a procedure using parent thread's VM without breaking something. So, it's most likely not an option...

Then Windows. SetWaitableTimer can also take a callback function. And according to MSDN, the callback function will be executed on the same thread.
The completion routine will be executed by the same thread that called SetWaitableTimer. This thread must be in an alertable state to execute the completion routine. It accomplishes this by calling the SleepEx function, which is an alertable function.
Using Waitable Timers with an Asynchronous Procedure Call
Now, I'm not sure what's alertable state exactly means. Seems the target thread should be sleeping and if so, sucks...

Hmmmm, it may not an easy thing to do.

2014-09-27

SRFI-30の紹介

(LISP Library 365参加エントリ)

SRFI-30は複数行のコメントを扱うためのSRFIです。説明するよりコードを見た方が早いので、まずはコードです。
#|
This is the SRFI
  #|
    Nested comment is also okay (unlike C)
  |#
|#
この形式のコメントはR6RS以降のSchemeからサポートされています。SRFIが標準に格上げされたものの一つともいえます。(逆に言うとR5RS以前は複数行コメントは標準ではなかったという・・・)

実はこのSRFIで定義されているBNFをよくみると入れ子のコメントは扱えないようになっています。これはSRFIが決定されてからの議論で修正案が出ていて、参照実装をBNFにするとこうなるみたいです。
<comment> ---> ; <all subsequent characters up to a line break>
             | <srfi-30-comment>

<srfi-30-comment> ---> #| <srfi-30-comment-constituent>* |* |#

<srfi-30-comment-constituent> ---> #* <srfi-30-ordinary-char>
                                 | |* <srfi-30-ordinary-char>
                                 | #* <srfi-30-comment>

<srfi-30-ordinary-char> ---> <any character but # or |>

どうでもいい小話なのですが、この形式のコメントを使うとたまにEmacsがおかしなシンタックスハイライトをするようになるので個人的には多用していないです。求む回避方法。

今回はSRFI-30を紹介しました。

2014-09-26

簡単なサーバプログラム用フレームワーク

フレームワークというほどたいそうなものでもないのだが、何かしらサーバを書く際に唱えるおまじない部分を勝手にやってしまおうというもの。そろそろちょっとしたサーバがあると便利だよなぁという願望のもとえいや!っと書いてみた。

とりえあず、エコーサーバはこんな感じで書ける。
(import (sagittarius socket) (net server))

(define (handler socket)
  (let ((bv (socket-recv socket 255)))
    (socket-send socket bv)))

;; creates server object
(define server (make-simple-server "5000" handler))

;; start!
(start-server! server)
handlersocket-acceptで作られたソケットを受け取る。ちなみにフレームワーク側でソケットは閉じてくれるので明示的に閉じる必要はない。(閉じても特に痛くはないが)

これだけだと特にありがたみもないのだが、オプション引数で設定を取ることができる。こんな感じ。
(import (sagittarius socket) (net server))

(define (handler socket)
  (let ((bv (socket-recv socket 255)))
    (socket-send socket bv)))

;; server has daemon thread which watches :shutdown-port
;; for shutdown the server.
;; exception handler will be invoked when handler
;; raises an error.
;; given max-thread > 1 makes the server creates a
;; thread for each request. using (util concurrent)
(define config (make-server-config :shutdown-port "8888"
                                   :exception-handler (lambda (e s) (print e))
                                   :max-thread 10))

(define server (make-simple-server "5000" handler config))

(start-server! server)
上記の設定だと、最大スレッド数10、サーバを閉じる用のポート8888(この設定だとつないだ瞬間落とす)に例外ハンドラという感じになる。これ以外にもTLSソケットとかある。

(どうでもいいdesign rationale) なんでキーワード引数じゃなくconfigオブジェクトにしたかというと、こうしておくと拡張が楽かなぁという希望的観測があったからだったりする。例えばHTTPサーバを書こうと思った場合に継承してなんとかできないかぁという。どうなるかは実際に拡張を書いて見ないと分からないという・・・

ついでといっては何ではあるのだが、これを書くために(util concurrent)というJavaのjava.lang.concurrentにインスパイアされたライブラリを書いたりした(ぶっちゃけ名前だけ・・・中身は性質上にても似つかないという・・・)。中身はSRFI-18があれば限りなくR6RSポータルになっているが、SRFI-18をサポートしてる処理系の方が少ないという罠もある。

2014-09-20

SRFI-29の紹介

、(LISP Library 365参加エントリ)

SRFI-29は名前の通りローカライズ(localiseのいい訳募集)のためのSRFIです。世の中英語で書いておけば大体OKな風潮ではありますが、エラーメッセージ等の言語を変更したい場合などに使える(かもしれない)ものです。

言語や地域の設定は以下のようにします。
(import (srfi :29))

(current-language)
;; returns current language (e.g. en)

(current-language 'fr)
;; sets language to French

(current-country)
;; returns current country (e.g. us)

(current-country 'nl)
;; sets country to Netherlands

(current-locale-details)
;; returns list of details (e.g. (utf-8))

(current-locale-details '(utf-8))
;; sets details
処理系によってはこの辺の情報を環境変数からとってきたりもします。(e.g. Gauche、Sagittarius)

言語ごとにメッセージを設定するにはdeclare-bundle!を使います。store-bundle!及びload-bundleは可能であればメッセージの設定を永続化及び読み込みを行います。
(let ((translations
       '(((en) . ((time . "Its ~a, ~a.")
                (goodbye . "Goodbye, ~a.")))
         ((fr) . ((time . "~1@*~a, c'est ~a.")
                (goodbye . "Au revoir, ~a."))))))
  (for-each (lambda (translation)
              (let ((bundle-name (cons 'hello-program (car translation))))
                (if (not (load-bundle! bundle-name))
                    (begin
                     (declare-bundle! bundle-name (cdr translation))
                     (store-bundle! bundle-name)))))
             translations))
上記はSRFIの例からですが、load-bundlebundle-name(この場合はhello-program)の読み込みを試み、失敗すればdeclare-bundle!で設定、store-bundle!で永続化を試みます。実際に設定されたメッセージを取得するにはlocalized-templateを使います。

このSRFIではformatの拡張も定義されていて、~[n]@*n番目に与えられた引数を参照します。例えば以下のような手続きを定義します(SRFIの例です)
(define localized-message
  (lambda (message-name . args)
    (apply format (cons (localized-template 'hello-program
                                            message-name)
                        args))))

(let ((myname "Fred"))
  (display (localized-message 'time "12:00" myname))
  (display #\newline)

  (display (localized-message 'goodbye myname))
  (display #\newline))
;; If current language is 'fr' then
;; prints 'Fred, c'est 12:00.'
;; and    'Au revoir, Fred.'
多少端折った説明になったのは僕自身はこのSRFIを使っていないので、今一使いどころを把握していないからなのですが、まぁ、こういうものだという部分は伝えられたかと思います。

今回はSRFI-29を紹介しました。

2014-09-12

SRFI-28の紹介

(LISP Library 365参加エントリ)

SRFI-28は基本な整形文字列です(訳難あり)。CLでおなじみのformat手続きをSRFIで提供するというものです。ただし、使用できる置換文字は~a~sのみの非常に基本的なものです。(名前どおりですね)

使い方は以下の通り。
(format "~a~%" Hello world)
;; -> "Hello world"
CLと違い、format文字列の前に#tを入れてもエラーになります。~adisplay~swriteが使われます。

参照実装では与えられたformat-stringをリストにしていますが、処理系によっては文字列の参照はO(1)で行われるのでstring-refで行った方が高速になるかもしれません。メモリスペースも多少節約できます。ひょっとしたら処理系によっては文字列は文字のリストでstring->listが時間、空間ともにO(1)で終わるものもあるかもしれません(少なくともR5RS以降では規格違反ではありますが)。
 
今回はSRFI-28を紹介しました。

2014-09-10

Is the condition continuable?

Since R6RS, Scheme has continuable exception which I think a good thing so that libraries may choose its behaviour when warning happened. R6RS has even the condition type &warning to let users know this. A bad thing is that, there is no way to know how the condition is raised. Think about this piece of code.
(import (scheme base) (scheme write))

(define-syntax safe-execute
  (syntax-rules ()
    ((_ expr ...)
     (with-exception-handler
      (lambda (e) #t)
      (lambda () expr ...)))))

(guard (e (else (display e) (newline) (raise e)))
  (safe-execute (raise "error huh?")))
The safe-execute just wraps given expression with with-exception-handler so that it can propagate non continuable condition to caller but can continue the process if the condition is just an warning. Now the problem is that, it doesn't propagate the raised condition as it is but modifies to something &non-continuable. For example, if you write the same code in R6RS and run it on Chez Scheme then the original condition's information disappears. (not sure if this is a bug of Chez though.)

So to keep my mind calm and mental health as healthy as possible, it is better to detect if the given condition is raised by raise or raise-continuable. However there is no way to do it with portable way. If you are an R6RS user, you may have slight hope, which is checking &warning or &non-continuable. If a script just wants to tell you an warning, then it usually raises an &warning condition. Thus checking this would make you a bit happy. Although, raise can take any Scheme object including &warning so this solution depends on the behaviour or philosophy of libraries. Moreover, guard without else needs to re-raise the caught condition with raise-continuable. This may cause something unexpected result if such a guard expression is wrapped by with-exception-handler.

Now, look at R7RS. It becomes totally hopeless. It doesn't have condition type, so the only hope that R6RS has is gone. The behaviour of all of related procedures and macro are the same as R6RS and it doesn't provide a procedures which can check if the condition is continuable or not, either. So this is totally depends on implementations.

If this is the case, then how the implementations behave. I've tested above piece of code with 4 implementations, Sagittarius, Chibi, Gauche and Foment. The results are followings;
  • Sagittarius - compounded the condition with &non-continuable
  • Chibi - changed condition with "exception handler returned" message (I guess)
  • Gauche - didn't print message at all (bug?)
  • Foment - propagated original condition.
For Gauche, if I changed raise to error it did print an error object. So it may not allow user to raise non condition object.

I'm not yet sure how important handling runtime exception is on Scheme. I've never written code that considers error other than just catching and logging. So this may be a trivial case.

2014-09-09

FFIバインディングは人間が手で書くものではない

というのを1年前に掲げて絶賛放置していたプロジェクトを何とか動くところまで持っていった。

https://github.com/ktakashi/sagittarius-ffi-helper

前は確かGTkか何かのバインディングを書くのが嫌でこれ作ったんだけど、GTkのバインディングを書く方を放置プレイに追い込んでしまったので同じく放置されていた。っで、最近DB2を扱う必要が出てきて、わざわざSQL走らせるのにGUI起動視するとか馬鹿らしいのでDBDが要るということから、あれよあれよと動くまで持っていった。

0.5.7で動くんだけど、生成されるコードは0.5.8用という仕様。理由は0.5.7のFFIは共用体のサポートがないからだったりする。逆に言えば、共用体がないのであれば、0.5.7でも動く(はず)。

簡単な仕様としては、マクロで定義された定数、typedef、構造体、共用体、列挙子なんかはそれなりに出力される。関数は可変引数にまだ対応してないのでそれがあると死ぬ。genbindが生成用のスクリプトで、合計で4つのファイルが生成される。構造体、共用体、列挙子とtypedefは定義と同名で、定数と関数はScheme的な名前に変更される。オプションで制御可能。

中身が非常に汚いので、綺麗にリファクタリングしてくれる奇特な方がいたら大歓迎。

これからはFFIバインディング書くのが楽になりそうな雰囲気が出てきた。(っが何時までたっても必要ドリブンなので、気の向くまま何かを書くということはないが・・・)

2014-09-06

syntax-caseで嵌った話

前にも似たような経験をしてTwitterに投げただけでまとめてない気がしたので書いておく。

問題になるのは以下のようなコード。
(import (rnrs))

(define-syntax define-foo
  (syntax-rules ()
    ((_ name)
     (begin
       (define name 'foo)
       (letrec-syntax
           ((gen (lambda (x)
                   (syntax-case x ()
                     ((k proc)
                      (with-syntax ((bar (datum->syntax #'k 'bar)))
                        #'(define bar proc))))))
            (get (syntax-rules ()
                   ((_) (gen (lambda (o) o))))))
         (get))))))

(let ()
  (define-foo name)
  (bar 'a))
期待するのはlet内のbarが参照可能であることなのだが、実際にはこれは見えない。Sagittarius類似コードを書いていたので「またマクロのバグか」と思っていたのだが、他の処理系でもエラーになる。自分の処理系ほど信じていないという切ない話ではあるのだが、よくよく考えればエラーになるのが筋なのである。

R6RSの構文オブジェクト周りを理解するのは骨が折れるのだが、今回の話はdatum->syntaxなのでその定義を見てみよう。
Template-id must be a template identifier and datum should be a datum value. The datum->syntax procedure returns a syntax-object representation of datum that contains the same contextual information as template-id, with the effect that the syntax object behaves as if it were introduced into the code when template-id was introduced.
 datum->syntaxによって生成される構文オブジェクトはtemplate-idと同じコンテキストの構文オブジェクトになる。これを踏まえて上記のコードをかなり目を凝らして見てみると、datum->syntaxのコンテキストとlet内のbarのコンテキストは違うように見える。letで作成されるコンテキストA、define-foo内のマクロ作成されるコンテキストBという風に見る(のだと思う)。AはBの外側のコンテキストと取れる。これと健全性の定義を照らし合わせてみる。
A binding for an identifier introduced into the output of a transformer call from the expander must capture only references to the identifier introduced into the output of the same transformer call. A reference to an identifier introduced into the output of a transformer refers to the closest enclosing binding for the introduced identifier or, if it appears outside of any enclosing binding for the introduced identifier, the closest enclosing lexical binding where the identifier appears (within a syntax <template>) inside the transformer body or one of the helpers it calls.
 これが今一理解できてないのではあるが、外側のコンテキストは内側のコンテキストを参照できないと読めなくもない。(内側のコンテキストが先に作られるので、先にできた束縛を後から作られたものが参照可能だと健全性が壊れるような気がする。) コードをこう書き換えると分かりやすいかもしれない。
(import (rnrs))

(define-syntax define-foo
  (syntax-rules ()
    ((_ name)
     (begin
       (define name 'foo)
       (define-syntax gen 
         (lambda (x)
           (syntax-case x ()
             ((k proc)
              (with-syntax ((bar (datum->syntax #'k 'bar)))
                #'(define bar proc))))))
       (define-syntax get
         (syntax-rules ()
           ((_) (gen (lambda (o) o)))))
       (get)))))

(let ()
  (define-foo name)
  (bar 'a))
これなら、上記の解釈が正しいと仮定すると、getとgenによって作られたbarがlet内にあるbarとは別物に見える。

この辺に詳しい人の突込みが待たれるところである。

捕捉
ちなみに、Sagittariusではletを取り除いてやると動いてしまうのだが、これは上記の解釈によればバグである。 っが、今のところ直す気はない。(MPが足りてない)

2014-09-03

Resolving let-method (2)

I've got sharp comment on previous article. Apart from the comment, I've found sort of critical issue on thread local storage solution. That is evaluating library form in eval won't add method to generic function. Well library form is not allowed to evaluate with eval on both R6RS and R7RS however Sagittarius allows it. (And I might have already written such code ...)

So forget about thread local storage. For now add-method checks current environment whether or not it's a child environment which is created by either environment procedure or a thread. The name child environment may confuse you but I just don't have any good name for this, so bare with it :) If add-method is called in child environment then it adds method to only in that context. If not, then adds globally.

Difference? Well sort of the same but it has now a way to affect changes globally. In the remote REPL situation discussed in previous article comment, it can be done with with-library macro. Other changes are only in the child context.

;; in remote REPL and we want to apply a patch
(import (sagittarius control))

(with-library (foo)
  ;; fix it
  (define-method bar ...))
This is just a fix before I forget, so it's time to read the paper.

2014-09-02

Resolving let-method

The previous article showed that there is a multi threading issue on let-method. In general, current Sagittarius adds generic method globally even whenever it's defined. So if the load loads a script with define-method then the generic method is added to the global binding. Thus the effect is globally done even though it's loaded in child thread.

This is not a good behaviour I believe so I've changed it. Current head has following behaviour;
  • If a method is defined in main thread - adds method globally
  • If a method is defined during importing a library - ditto
  • If a method is defined in child thread and not library importing period - adds thread local storage.
  • Generic functions are inherited from parent thread but child thread can't contaminate parent.
The thread local storage is VM's register I've added, generics (not sure if the name is proper but reasonable isn't it?). The changes are done in three places, add-method, remove-method and compute-methods. There are slight change of slot accessor of generic function as well but this is trivial.

The change of compute-methods is not a big one. It now just considers generic methods of current thread. Like I mentioned above, generic methods are located two places, one is generic function's methods slot and the other one is thread local storage. Thus compute-methods needs to get all methods both the slot and storage.

add-method and remove-method are a bit more tricky. First it needs to detect whether or not it's running on main thread or during library importing period. If the definition is executed on that term then it adds the methods to generic function's slot. If not, then it adds thread local storage with some more information. (currently maximum required argument number.)

Now following piece of code runs as I expected.
(import (rnrs) (clos user) (srfi :1) (srfi :18) (srfi :26))
 
(define-generic local)
 
(define (thunk)
  (thread-sleep! 1)
  (let-method ((local (a b c) (print a b c)))
    (thread-sleep! 1)
    (local 1 2 3))
  (local "a" "b" "c"))
 
(let ((ts (map thread-start! (map (cut make-thread thunk &lt;>) (iota 10)))))
  (for-each thread-join! ts))
;; may prints some of the value
;; then raises an error.
The solution itself might be a bit ugly (treating generic function specially) but behaving properly is more important.

let-method

Sagittariusはlet-methodという総称関数のスコープを限定する構文をもっているのだが、これとマルチスレッドが絡むとうまく動かないという話。

例えば以下のようなのを考えてみる。
(import (rnrs) (clos user) (srfi :1) (srfi :18) (srfi :26))

(define-generic local)

(define (thunk)
  (thread-sleep! 1)
  (let-method ((local (a b c) (print a b c)))
    (thread-sleep! 1)
    (local 1 2 3))
  (local "a" "b" "c"))

(let ((ts (map thread-start! (map (cut make-thread thunk <>) (iota 10)))))
  (for-each thread-join! ts))
let-methodの外側で呼ばれるlocalメソッドはどのような場合でもエラーを投げることが期待されるのだが、実はこれが期待通りには動かない。理由はいたって簡単で、スレッドAが二度目のlocal呼び出しをする際にスレッドBがlet-method内であればlocal自体は特殊化されたメソッドを持っていることになる。あまり使わない構文な上に、マルチスレッド環境のことなど頭から抜け落ちていたのでこういうことに気付かなかった。

では、どうするかということもついでに考えてみる。現状では総称関数はスレッド関係なくグローバルに影響を与えるのだが、こいつをスレッド毎にしてしまえばいいだけの話ではある。総称関数だけを特別視するというのは多少気持ち悪い部分もあるのだが、パラメタと同じでVMにそれ様のレジスタを追加しスレッドが作成されたらコピーすればいいという話になる。そうすることで大元の総称関数は変更されない。

問題はdefine-genericもdefine-methodも単なるマクロで、内部的には総称関数を作ってdefineで定義しているだけという部分と、VMは識別子を一度参照するとGLOCに置き換えるという点である。最初の問題は実はそんなに大きくなく、束縛を作成する際に値が総称関数であれば現在のVMに追加してやればいい。(そもそも子スレッドで束縛を作るというのはいかがなものかという話もあるのだが。) GLOCの問題はGLOCがコンパイルされたコードに埋め込まれつつ、この中身が基本変更されないという前提があることに起因する。GLOCがあるとコピーされた総称関数が参照できないということになる。

とりあえず思いつく限りでは2つ解決策がある。
  • 総称関数の参照はGLOCにしない
  • 総称関数の呼び出し時にうまいこと解決する
一つ目は全体のパフォーマンスに影響を与えそうではあるが、常に参照を解決するようにして束縛を探す際にコピーされた総称関数を返してやればよさそうである。
二つ目はVMのレジスタが大元の総称関数とコピーされたものの紐付けを持っておき、呼び出し時にコピー側に解決するというもの。単なる参照として別の手続きに渡された際にどう解決するかというもの。GREFが走るたびにチェックを設けていてはGLOCの意味がない気がするが、総称関数を扱う手続き全てにコピーを探す何かを入れるのはだるい。(本質的にはadd-methodとremove-methodだけを特別視すればいいような気がしないでもないが、ちと自信がない。)

あまり使わない機能な上に直すとパフォーマンスに影響がでるから割と腰が重めである・・・

追記
add-methodがスレッドローカルなストレージにメソッドを格納してcompute-methodsがその辺をうまいこと何とかすればいけそうな気がしないでもない気がしてきた。 add-methodにオプション引数としてスレッドローカルか判別するフラグつけて、let-methodが呼び出すadd-methodはそのオプションを受け付けるようにしてやればよさそう。(もしくはadd-method-localを作るか。) remove-methodも同様にしてやる必要があるが、変に上記のようにごにょごにょするよりはすっきりしているかもしれない。

Ambiguous WSDL behaviour?

I haven't read WSDL 1.1 specification thoroughly yet but it seems there is an ambiguous behaviour to create a XML message.

I've prepared following files (it's extremely simplified to make this article short).
example.wsdl
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<definitions targetNamespace="http://example.com/" name="ExampleService" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://example.com/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">
  <types>
    <xsd:schema>
      <xsd:import namespace="http://example.com/" schemaLocation="schema1.xsd"/>
    </xsd:schema>
    <xsd:schema>
      <xsd:import namespace="com.example" schemaLocation="schema2.xsd"/>
    </xsd:schema>
  </types>
  <message name="create">
    <part name="parameters" element="tns:create"/>
  </message>
  <message name="createResponse">
    <part name="parameters" element="tns:createResponse"/>
  </message>
  <message name="ExampleServiceException">
    <part name="fault" element="tns:ExampleServiceException"/>
  </message>
  <portType name="Interface">
    <operation name="create">
      <input message="tns:create"/>
      <output message="tns:createResponse"/>
      <fault message="tns:ExampleServiceException" name="ExampleServiceException"/>
    </operation>
  </portType>
  <binding name="ExampleInterfacePortBinding" type="tns:Interface">
    <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
    <operation name="create">
      <soap:operation soapAction=""/>
      <input>
        <soap:body use="literal"/>
      </input>
      <output>
        <soap:body use="literal"/>
      </output>
      <fault name="ExampleServiceException">
        <soap:fault name="ExampleServiceException" use="literal"/>
      </fault>
    </operation>
  </binding>
  <service name="ExampleService">
    <port name="ExampleInterfacePort" binding="tns:ExampleInterfacePortBinding">
      <soap:address location="REPLACE_WITH_ACTUAL_URL"/>
    </port>
  </service>
</definitions>
schema1.xsd
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0" targetNamespace="http://example.com/" xmlns:tns="http://example.com/" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:ns1="com.example">

  <xs:import namespace="com.example" schemaLocation="schema2.xsd"/>

  <xs:element name="ExampleServiceException" type="tns:ExampleServiceException"/>

  <xs:element name="create" type="tns:create"/>

  <xs:element name="createResponse" type="tns:createResponse"/>

  <xs:complexType name="create">
    <xs:sequence>
      <xs:element name="request" type="ns1:Request" minOccurs="0"/>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="createResponse">
    <xs:sequence>
      <xs:element name="response" type="ns1:Response" minOccurs="0"/>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="ExampleServiceException">
    <xs:sequence>
      <xs:element name="message" type="xs:string" minOccurs="0"/>
    </xs:sequence>
  </xs:complexType>

</xs:schema>
schema2.xsd
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0" targetNamespace="com.example" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:ns2="com.example">

  <xs:import namespace="http://example.com/" schemaLocation="schema1.xsd"/>

  <xs:complexType name="Request">
    <xs:sequence>
      <xs:element name="id" type="xs:string" minOccurs="0"/>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="Response">
    <xs:sequence>
      <xs:element name="id" type="xs:string" minOccurs="0"/>
    </xs:sequence>
  </xs:complexType>

</xs:schema>
Now, I've created a sample message on Soap UI and online WSDL analyser. The result of create messages are followings;
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:exam="http://example.com/">
   <soapenv:Header/>
   <soapenv:Body>
      <exam:create>
         <!--Optional:-->
         <request>
            <!--Optional:-->
            <id>?</id>
         </request>
      </exam:create>
   </soapenv:Body>
</soapenv:Envelope>
<ns1:create xmlns:ns1='http://example.com/'>
<!-- optional -->
  <request>
<!-- optional -->
    <ns2:id xmlns:ns2='com.example'>?XXX?</ns2:id>
  </request>
</ns1:create>
The point is that online WSDL analyser's one has namespace com.example and Soap UI one doesn't. Well, from the beginning, I don't understand why both request element doesn't have namespace at all.

As far as I know, JAX-WS requires Soap UI format so this is written some where in spec?

2014-08-30

SRFI-27の紹介

(LISP Library 365参加エントリ)

SRFI-27は乱数ビットのソースです。 名前で分かるとおり、乱数の生成及びその生成源を扱うSRFIです。最も簡単な使い方は以下。
(import (srfi :27))

(random-integer 100)
;; -> random integer up to 100

(random-real)
;; -> random flonum range between 0 < x < 1
このスクリプトを複数回流した際に返される値がランダムになるかは実装依存です。例えば、Sagittariusでは最初の1回目は常に1が返ります。

さすがにそれは嬉しくないので、以下の結果を毎回ランダムにする方法が用意されています。
(random-source-randomize! default-random-source)

(random-integer 100)
default-random-sourcerandom-integerrandom-realで使用される乱数ソースです。それをrandom-source-randomize!でいい感じにシャッフルします。

デフォルトを変更したくないという我侭な要望にも柔軟に対応可能です。 以下のようにします。
(define my-random-integer
  (let ((s (make-random-source)))
    (random-source-randomize! s)
    (random-source-make-integers s)))

(my-random-integer 100)
;; random number

(random-integer 100)
;; 1 (on Sagittarius)
random-source-state-ref及びrandom-source-state-set!で乱数ソースの状態を取得、設定することも可能です。乱数ソースが何であるかは言及されていないのですが、書き出し可能なオブジェクトである必要があります。例えば、Sagittariusではバイトベクタ、Gaucheではu32ベクタ、Chibiは数値、Mosh及びYpsilon(ポータブルSRFI)ではリスト、Racketはベクタになっています。

今回はSRFI-27を紹介しました。

2014-08-27

最適化

ちょっとした最適化をコンパイルに入れた。具体的にはインポートした束縛でキャッシュ可能なものは定数展開してしまうというもの。以下がその例。
(library (foo)
    (export a)
    (import (rnrs))
  (define a 'a))
(import (rnrs) (foo))
;;(set! a 'b) ;; uncomment this would also work...
(disasm (lambda () (print a)))
こんな感じのライブラリをインポートすると
;; size: 5
;;    0: CONST_PUSH a
;;    2: GREF_TAIL_CALL(1) #<identifier print#user (0x80402708):0>; (print a)
;;    4: RET
こんな感じで、GREF_PUSHの変わりにCONST_PUSHが使われるというもの。これだけだと、実はあんまり嬉しくないんだけど、これにコンパイル時の手続き呼び出しが加わるとかなり最適化ができる。例えばaが文字列"1234"で、スクリプトが(print (string->number a))だとすると、string->numberがコンパイル時に解決されて数値1234が直接VMインストラクションとして出される。まぁ、そんなに上手いことはまるケースは少ないだろうけど、こういうのは入れておくと後で効いてくるというのが経験側から学んだことなので入れておいて損はないだろう。

現状で気に入らないのはset!の挙動なのだが、再定義と代入は別ものとしてエラーにした方が精神衛生上いいような気がする。スクリプト上の環境(+evalの環境)は再定義+代入可能にしているのでこれが可能なのだが(#!compatibleをつけても同様)、禁止するとREPL上でも禁止になるという弊害もある。そうは入ってもREPL上で(set! + 'hoge)とかやるかという話にもなるのだが、例えばMoshとChezはこれを禁止している(psyntaxがかね?)。ちなみに、NMoshとYpsilonは許容している(NMoshは奇妙な挙動をするけど)。

ちなみに、再定義もしくは代入された後は定数展開されない。というか、同一ライブラリで定義された場合はされないという話。これは、例えばGambit benchmarkのcompilerみたいなの対策だったりする(展開されると正しい結果が出ない場合)。ただし、library及びdefine-libraryフォーム内では別のロジックが走るので、展開される可能性はある。でも、よく考えれば、定数しかやらないので展開してしまってもいいかもしれない。後で考えよう。

追記
いや、やっぱり同一ライブラリ内では駄目だな。以下のようなのが困る。
(define b 'b)
(define (foo) (print b))
(foo)
(set! b 'c)
(foo)
これを定数展開してしまうと、二度目のfooが正しく動かない。

追記2
インポートされた束縛に対するset!は禁止することにした。再定義はOK。そういえばこの変更でR6RS/R7RS準拠のevalが書けなくもないのだが(定義禁止等)、まぁそこまでする必要は今のところないかなぁ。

2014-08-23

SRFI-26の紹介

(LISP Library 365参加エントリ)

SRFI-26はカリー化を除いたパラメタの特殊化表記です。日本語にすると意味が分かりませんが(正しく訳せているのかすら疑問) 、要するにcutcuteです。どちらも手続きを作成するマクロです。使い方は以下:
(cut cons a <>)
;; -> (lambda (tmp) (cons a tmp))

(cut list a <> <>)
;; -> (lambda (tmp1 tmp2) (list a tmp1 tmp2))

(cut list a <> <...>)
;; -> (lambda (tmp1 . xs) (apply list a tmp1 xs))

(cute cons (+ a 1) <>)
;; -> (let ((a1 (+ a 1))) (lambda (tmp) (cons a1 tmp)))
どちらのマクロも第一引数を手続きとみなし、残りをその手続きの引数とします。<>及び<...>はプレースホルダーで、作成された手続きに渡される引数に置換されます。出現する順番どおりに引数に展開されます。cutは引数をそのままlambdaに展開し、cuteの方はプレースホルダーである<>以外の引数を評価を一度だけ行うことを保障します。

プレースホルダーの使い方ではまるのが以下の例です。
(cut cons a (list b <>))
;; -> (lambda () (cons a (list b <>)))
プレースホルダーはcutもしくはcuteと同じ深さにいないといけません。個人的にこれは不便だなぁと思う点ではあるのですが、ネストを考慮するとsyntax-rulesで書けない(もしくはものすごく頑張らないといけない)ので、まぁしょうがないのではないでしょうか。

今回はSRF-26を紹介しました。

2014-08-19

Performance turning - I/O

The R7RS benchmark showed that I/O was slow in Sagittarius. Well not quite, in R7RS library read-line is defined in Scheme whilst get-line is defined in C.This is one of the reason why it's slow. There is another reason that makes I/O slow which is port locking.

Sagittarius guarantees that passing a object to the port then it writes it in order even it's in multi threading script. For example;
(import (rnrs) (srfi :18) (sagittarius threads))

(let-values (((out extract) (open-string-output-port)))
  (let ((threads (map (lambda (v) 
   (make-thread (lambda ()
           (sys-nanosleep 3)
           (put-string out v)
           (newline out))))
        '("hello world"
   "bye bye world"
   "the red fox bla bla"
   "now what?"))))
    (for-each thread-start! threads)
    (for-each thread-join! threads)
    (display (extract))))
This script won't have shuffled values but (maybe random order) whole sentence.

To make this, each I/O call from Scheme locks the given port. However if the reading/writing value is a byte then the locking is not needed. Now we need to consider 2 things, one is a character and the other one is custom ports. Reading/writing a character may have multiple I/O because we need to handle Unicode. And we can't know what custom port would do ahead. Thus for binary port, we don't have to lock unless it's a custom port. And for textual port, we can use string port without lock.

Now how much performance impact with this change? Following is the result of current version and HEAD version:
% ./bench sagittarius tail
Testing tail under Sagittarius
Compiling...
Running...
Running tail:10

real    0m26.155s
user    0m25.568s
sys     0m0.936s

% env SAGITTARIUS=../../build/sagittarius ./bench sagittarius tail

Testing tail under Sagittarius
Compiling...
Running...
Running tail:10

real    0m19.417s
user    0m18.703s
sys     0m0.904s
Well not too bad. Plus this change is not for this particular benchmarking which uses read-line but for generic performance improvements. Now we can finally change the subjective procedures implementation. The difference between get-line and read-line is that handling end of line. R7RS decided to handle '\r', '\n' and '\r\n' as end of line for convenience whilst R6RS only needs to handle '\n'. Following is the result of implementing read-line in C.
% env SAGITTARIUS="../../build/sagittarius" ./bench -o -L../../sitelib sagittarius tail

Testing tail under Sagittarius
Compiling...
Running...
Running tail:10

real    0m5.031s
user    0m4.492s
sys     0m0.795s

Well it's as I expected so no surprise.

Performance turning - Windows (MSVC)

It turned out that Windows version of Sagittarius is extremely slow. If I try ack on Cygwin version then it can run about 60 sec (Core i7 3.40 GHz). Following is the result of three implementations that previous article mentioned.
% time gosh -r7 ack.scm
gosh -r7 test.scm  130.14s user 4.26s system 120% cpu 1:51.70 total

% time sagittarius ack.scm
sagittarius test.scm  54.48s user 3.01s system 124% cpu 46.022 total

% time chibi-scheme ack.scm
chibi-scheme test.scm  49.84s user 0.00s system 99% cpu 50.170 total

And this is the inside of "acm.scm".
(import (scheme base))
(define (ack m n)
  (cond ((= m 0) (+ n 1))
        ((= n 0) (ack (- m 1) 1))
        (else (ack (- m 1) (ack m (- n 1))))))

(ack 3 12)
Apparently Chibi is the fastest. And Sagittarius is not so slow. Well, I don't know why Gauche is slow in Cygwin environment. I think this is simply the performance of VM and its stack overflow handling. (at least on Sagittarius, not sure for others.)

Now let's see how is the Windows version's performance. Following is the result of ack using Cygwin's time command to see how slow it is.
D:>\cygwin\bin\time sash.exe ack.scm
0.00user 0.00system 1:12.13elapsed 0%CPU (0avgtext+0avgdata 220928maxresident)k
0inputs+0outputs (901major+0minor)pagefaults 0swaps
I don't know why it has some garbage but 30% slower. So indeed it is Windows version's issue. But why?

I think the reason why is it does not use direct threading due to the limitation of MSVC (if we use it should improve approx 30% of performance, so about 21 sec in this case?). However I've found this article: How not to make a virtual machine (label-based threading). Even though this article concluded not to emulate direct threading on MSVC however it wouldn't hurt to give it a shot.So I've modified VM a bit to emulate it (sources are in msvc32-emulate-direct-threading branch). Then run the above script.

Here is the result;
D:>\cygwin\bin\time.exe build\sash.exe ack.scm
0.00user 0.00system 1:40.56elapsed 0%CPU (0avgtext+0avgdata 220928maxresident)k
0inputs+0outputs (901major+0minor)pagefaults 0swaps
Well, it's always better to believe what people have done, I guess...So this really doesn't work. Now we only have 2 options, giving up or adopt to MinGW. Hmmmm.

2014-08-17

性能差

@SaitoAtsushiさんがLarcenyにあるR6RSベンチマークをR7RS用にして走らせた結果をツイートしていた。


Gaucheが速いのは分かっていたことなのだが(いずれ追い越す予定…未定…)、Chibiより遅いベンチがあるのは正直まずい。Chibiはランタイムが小さいためほとんどの手続きがSchemeで書かれているという特徴があるのだが、それより遅いのがあるということは基本的なVM等の動作が遅い可能性がある。

とりあえずChibiより遅いのが以下のベンチ
  • ack
  • cat
  • nucliec
  • quicksort
  • simplex
  • slatex
  • gcbench
  • mperm
こいつらに関わる手続きはすぐにでもパフォーマンスチューニングする必要がある。特にackなんて本当にシンプルなのでVMの性能がまずいということになる・・・(涙)

次いで、Gaucheに圧倒的に負けてるやつ
  • ctak
  • sum
  • sumfp
  • mbrot
  • mbrotZ
  • pnpoly
  • tail
  • read1
  • lattice
  • nqueens
結構あるのだが、このうち浮動小数点が関わってくるやつ(sumfp、mbrot及びmbrotZ)はちと分が悪いので後回し。Gaucheは浮動小数点数をある程度レジスタに持つのでキャッシュが効くうちはメモリ割付が発生しない(はず)。テキストポートが絡んでくるI/O周りも多少分が悪いところがあるのではあるが、何とかしたいところ。nqueensはどちらも絡まないのでVMもしくはコンパイラということになる。

所詮マイクロベンチマークという見方もあるかもしれないが、こういう地味な性能差は地道なチューニングの結果なのでここで手を抜くのはまずいというのが僕の考え方。

2014-08-12

What do you expect to be printed?

I was testing how include on Sagittarius works and found out something interesting.

Firstly, I've prepared 4 files related to library. The contents are very simple. Like this;
;; foo.sld
(define-library (foo)
    (import (scheme base))
    (export bar)
  (include "impl/bar.scm"))

;; impl/bar.scm
(include "buzz.scm")

;; impl/buzz.scm
(define bar 'bar)

;; buzz.scm
(define bar 'buzz)
Now I put those files following directory structure;
./ + foo.sld
   + impl
       + bar.scm
       + buzz.scm
   + buzz.scm
Then, wrote following script;
(import (scheme base) (scheme write) (foo))
(display bar) (newline)
The question is, what would be the expected value to be printed 'bar or 'buzz? I first expected to be print 'bar with Sagittarius but it was 'buzz. Then checked with Chibi which also printed 'buzz. At this point I thought, oh R7RS de-facto would be 'buzz. Well it wasn't. I've also check with Gauche and Foment and these printed 'bar.

I know why this happens actually. When the first include was processed then the current loading path returned to the same directly as "foo.sld". Then second include "buzz.scm" is processed. I don't know how Gauche and Foment do this properly (well R7RS doesn't specify how to resolve the path so both are proper behaviour though).

Well, by now I've never seen this type of code in anywhere other than in my test. But I would like to go more intuitive behaviour.

13th August, 2014
I've modified compiler to be able to handle above case. What I've changed is that
  • include and include-ci returns read expression and filename
  • compiler sets current load path after include is done according to above filenam
It's a bit ugly way to fix so I need to think how we can clean it up now.

2014-08-11

SQL in S-Expression

There is SXML which represents XML in S-Expression. If you're a professional programmer, it is very difficult to avoid using SQL (well, if you could, you are very lucky).

Writing SQL isn't so bad if the file is separated or the editor is smart enough to edit. However it's usually none of the case so I always need to suffer especially writing it in double quote. Now, Emacs is de-facto editor for all programmers (vim? why are you talking about jeans here? V.I.M.) and it's by default very good with editing s-expression. So if you can write SQL in s-expression then the world would be happier than before.

Now, there are bunch of projects that have the same idea I've got, CLSQL, SxQL, S-SQL for example (I think Clojure also has something similar but I'm not so familiar). The problem of them are very simple. It's using keyword which is not in R6RS/R7RS. Moreover, those use either reader macro or CLOS so not pure s-expression. What I want is light weight but easy to edit. (well, it is actually ok for me, Sagittarius has all of them anyway.)

So I'm thinking something like following;
(define ssql 
  '(select ((p id) (as (p first_name) name) (a street))
    (from (as person p))
    (inner-join (as address a) (on (= (p id) (a id_person))))
    (where (= (a country) "Nederlands"))))

(ssql->sql ssql)
;; "select p.id, p.first_name as name, a.street
;;  from person as p
;;  inner join address as a on p.id = a.id_person
;;  where a.count = 'Netherlands'" 
Hmmm, it looks parentheses are a bit too many so the readability is a bit lowered. Basically it doesn't have to be fancy but readable and easy to remember. So one-by-one mapping is ok. (if I want  OR-mapper, then I just need to construct it on top of it.)

If there is something similar in Scheme or better idea, I would like to know.