2017-12-17

95%の人は満足するけど残りの5%は不満を持ち得るシステムの5%に入ってしまった件

表題が示す通りなんだけど、そんな境遇に陥った。

今の会社に入って1年半たつのだが、買収があったりして給与システムの大幅な見直しみたいなのがあった。今までは、なんとなく評価された人が昇給されたりボーナスがあったりみたいな超おおざっぱな感じだったんだけど(特に決められたルールがなかった)、スケール制(ランク制?)みたいなのが導入されたり、固定値のボーナス(オランダ的には13ヵ月目ともいう)が導入されたりしてきた。

これだけ見ると改善があって、透明性が増したからいいじゃんなんだけど、導入されたシステムには頭打ち もあって、あるランクで最高額に到達したら昇給が発生しないのである。この状態で昇給するにはランクアップするしかない。僕はこの状態であるという通知を受けた。一応満額まで数パーセントあるように見えるが、微妙な曖昧性があるので、満額と言われてもおかしくない状態。

っで、現状ではランクアップの方法は不明かつシニアエンジニアとして雇われているので、この職責上でこの上ってなんになるんだろう的なのもある。

周りの反応を見るに、この状況にある被雇用者は本当に少数っぽくて、ちょっと話を聞いていただけだと、普通評価でも毎年3~4%の昇給が望めると喜んでいる人の方が多いくらいだった。いままで昇給のルールすらなかったのだから気持ちは分かるが…

このシステムが導入される際に一応プレゼンがあったんだけど、そこで言われたのが、「頭打ちになった際にはランクアップするために別のポジションに着く必要があるが、社内にそのポジションがなかったら社外で探すしかない」という旨の言葉だったりする。こういう状況の人間が発生することは分かっていたうえでのこの発言+特に救済(現状の職責より1ランク高いものを割り当てておくとか)をしなかったのは潔いなと思う反面、いま開発者が去るだけで入ってこない状況を軽めに見てるのかなぁとも思ったり。(もしくは僕は穀潰しとみなされているか、それはそれで悲しいが…)

今週のどこかで昇給についての面接があるらしいので、ランクアップの可能性があるのかないのか聞かないとなぁ。可能性0ならしょうがない、次の職場をまじめに探すかねぇ。

2017-11-24

プログラミング言語Schemeの学び方

これに触発されてみた。
調簡易なHTTPサーバーをR7RS+SRFIで作ってSchemeを学ぼうという話。スライド145にある項目をとりあえず列挙
  • Socketの扱い
  • 正規表現
  • リソースの開放
  • 並行処理
  • 文字列の扱い
【Socketの扱い】
Scheme標準にはないのでSRFI-106を使う。サーバーSocketはこう作る。
(define server-socket (make-server-socket "8080"))
そして、こんな風に待ち受ける。
(let loop ()
  (let ((socket (socket-accept server-socket)))
    (loop))
特に何もしないソケットがリークしまくるサーバーの出来上がり。

【正規表現】
Scheme標準にはないのでSRFI-115を使う。HTTPリクエストの最初の一行をパースする正規表現はこんな感じで書ける。
(define first-line
  '(: "GET" (+ space)
      (-> path (: "/" (+ ascii))) (+ space)
      "HTTP/" (: num "." num)))
こんな感じで使う
(cond ((regexp-matches first-line line) =>
       (lambda (m)
         (let ((path (regexp-match-submatch m 'path)))
           ;; get the content of the path
           ))))
サブマッチに名前は付ける必要はないが、あるとわかりやすい。

【リソースの開放】
Schemeに便利な汎用リソース開放構文というのはないので、都度用途に合わせて作ったり標準にあるものを用いる。例えば、ポートの開放はclose-portを使い、call-with-portを使えば、正常処理後にはポートを閉じてくれる。Socketの開放はsocket-shutodownsocket-closeを用いる。
サーバをであれば、以下のようなものが便利に使えなくもない。
(define (finish)
  (close-port in)
  (close-port out)
  (socket-shutdown socket *shut-rdwr*)
  (socket-close socket))
inoutはソケットポートである。

【並行処理】
Scheme標準にはないのでSRFI-18を使う。SRFI-18はプリミティブなスレッドとミューテックスしか提供しないので、高度なものが必要であれば自分で作る必要がある。
投げっぱなしスレッドは以下のように作れる。
(thread-start! (make-thread (lambda () (handle-request socket))))
処理系によってはスレッドの作成は高価な場合があるので、可能であればスレッドプール等は作っておきたいところ。R6RS処理系かつSRFI-18をサポートしているのであれば、拙作の(util concurrent)が使える。

【文字列の扱い】
スライドにあるような便利なものはない。連結したければstring-append等を使う必要がある。文字列操作は高価な場合があるので(例:参照にO(n)かかる)、使える場面ではポートを使いたいところ。

さて、上記全てを踏まえて非常に簡易なGETリクエストのみに対応したHTTPサーバは以下になる。R7RSではバイナリポートと文字ポートは分かれていて、処理系によっては厳しく分けてあつかう(特にR6RS/R7RSな処理系、Sagittariusなど)ので、I/Oの部分がどうしても煩雑になる。例えば、出力の際には文字列を一旦バイナリに変換している。

(import (scheme base)
        (scheme write)
        (scheme file)
        (srfi 18)
        (srfi 106)
        (srfi 115))

;; Assume all ASCII
(define (read-binary-line in)
  (let ((out (open-output-string)))
    (let loop ((b (read-u8 in)))
      (case b
        ((#x0d)
         (case (peek-u8 in)
           ((#x0a) (read-u8 in) (get-output-string out))
           (else (write-char (integer->char b) out) (loop (read-u8 in)))))
        (else (write-char (integer->char b) out) (loop (read-u8 in)))))))

(define (handle-request socket)
  (define in (socket-input-port socket))
  (define out (socket-output-port socket))
  (define first-line
    '(: "GET" (+ space)
        (-> path (: "/" (+ ascii))) (+ space)
        "HTTP/" (: num "." num)))
  (define (finish)
    (close-port in)
    (close-port out)
    (socket-shutdown socket *shut-rdwr*)
    (socket-close socket))
  (define (http-error status e)
    (define message (string->utf8 "Not okay"))
    (report-error e)
    (write-bytevector (string->utf8 "HTTP/1.1 ") out)
    (write-bytevector (string->utf8 (number->string status)) out)
    ;; laziness...
    (write-bytevector (string->utf8 " BOO\r\n") out)
    (write-bytevector (string->utf8 "Content-Type: text/plain\r\n") out)
    (write-bytevector (string->utf8 "Content-Length: ") out)
    (write-bytevector (string->utf8
                       (number->string (bytevector-length message))) out)
    (write-bytevector (string->utf8 "\r\n\r\n") out)
    (write-bytevector message out)
    (finish))
    
  (guard (e (else (http-error 500 e)))
    (let ((line (read-binary-line in)))
      (cond ((regexp-matches first-line line) =>
             (lambda (m)
               (let ((path (regexp-match-submatch m 'path))
                     (bout (open-output-bytevector)))
                 (guard (e (else (http-error 404 e)))
                   (let ((file (string-append "." path)))
                     (call-with-port (open-binary-input-file file)
                       (lambda (in)
                         (define buf (make-bytevector 1024))
                         (let loop ((n (read-bytevector! buf in)))
                           (write-bytevector buf bout 0 n)
                           (when (= n 1024)
                             (loop (read-bytevector! buf in))))))))
                 (write-bytevector (string->utf8 "HTTP/1.1 200 OK\r\n") out)
                 (write-bytevector (string->utf8 "Content-Type: text/plain\r\n") out)
                 (let ((bv (get-output-bytevector bout)))
                   (write-bytevector (string->utf8 "Content-Length: ") out)
                   (write-bytevector (string->utf8
                                          (number->string
                                           (bytevector-length bv))) out)
                   (write-bytevector (string->utf8 "\r\n\r\n") out)
                   (write-bytevector bv out)
                   (finish)))))
            (else (http-error 403 #f))))))

(define server-socket (make-server-socket "8080"))

(display "Starting server on port 8080") (newline)
(let loop ()
  (let ((socket (socket-accept server-socket)))
    (thread-start! (make-thread (lambda () (handle-request socket))))
    (loop))
もう少し簡単に書きたいと思ったら、Sagittariusに付属している(net server)を使うか、拙作Paellaを使うと簡単にHTTPサーバが書ける。後者はサーバというよりはWebアプリが簡単に書けると言うべきか。

2017-11-08

スレッドの軽量化

Sagittariusはスレッドの作成が重い。理由は至って簡単でスレッド毎にVMを複製するからである。あまり気にするほどスレッドを使っていなかったのだが、最近(というか昨日)Paellaに非同期的なのを入れた際にこれはまずいと思いだした。何がまずいかというと、Paellaに入れた非同期構造は、サーバーからソケットの管理を外した後にスレッドを作ってその中でリクエストを処理するというものだからだ。つまり、スレッドの作成の重さがそのままボトルネックになる。

スレッドの生成で最も重いのはVMスタックを割り当てる部分だと大まかにあたりをつけてはいた。ついでに、VMスタックをCスタック上におければよくね?とも考えてはいた。ずっと思っていただけで実行には移さなかったのだが、ここに来てちと重要になりそうなのでえいや!っと試してみることにした。

スレッド=VMということはスレッドの寿命=VMの寿命でもあるので、開始時にスレッドのスタックからVMスタックを割り付ければ問題ないはず。ということでそんな感じのコードを書いて適当なベンチマークを行ってみた。以下はベンチマークのコード

(import (rnrs) (srfi :1) (srfi :18) (time))

(define data (iota 10000))

(let ((threads
       (time (map (lambda (i)
                    (thread-start! (make-thread (lambda () i)))) data))))
  (assert (equal? data (map thread-join! threads))))
スレッドの生成時間のみを測りたいので、こんなに単純。っで以下が結果(環境 Ubuntu 16.04 64bit Intel® Core™ i7-6820HQ CPU @ 2.70GHz × 8):
元のコード
$ sash thread-bench.scm

;;  (map (lambda (i) (thread-start! (make-thread (lambda () i)))) data)
;;  2.626753 real    3.012000 user    0.256000 sys
改良版
$ ./build/sagittarius -Dbuild thread-bench.scm

;;  (map (lambda (i) (thread-start! (make-thread (lambda () i)))) data)
;;  0.239091 real    0.120000 user    0.224000 sys
ちょっと出来過ぎな感じもするが、効果はありっぽい。まぁ、生成数をひとけた減らすと3倍程度の改善になるので、メモリの圧迫が減っただけとも言える(それが目的なのではあるが)。

2017-10-29

アクター

メッセージパッシングとも言う。

Sagittariusには(util concurrent)があるのだが、今までこのスタイルのライブラリを追加してなかった。理由としては
  • 実装自体はトリビアルであること
  • ライブラリにするにはアイデアの練りが足りないこと
の二つが主であった。のだが、あまりにも似たようなパターンを書くので重い腰を上げることにした。以下のように使う。
(import (rnrs) (util concurrent))

(define actor
  (make-shared-queue-channel-actor
    (lambda (input-receiver output-sender)
      (let loop ()
        (let ((in (input-receiver)))
          ;; do whatever with the input
          (output-sender (result)) ;; if output should be sent
          (loop))))))

(actor-send-message! actor 'message) ;; send a message to the actor
(actor-receive-message! actor)
わざわざチャンネルに使われているキュー名が入っているのは以下の理由から
  • shared-priority-queueバージョンのアクターもある
  • 入力と出力にどんなキューが使われるのか分からないので、make-actorみたいなのにはできない
二つ目の理由からmake-actor手続きは入力と出力を作る手続きを受け取るようになっている。

これをアクターと呼んでいいのかは正直よくわからないが、広義ではアクターモデルだろうということで。

2017-10-27

バグ取り

Sagittariusには(net server)というライブラリがあって、それを使うと割と簡単にノンブロッキングなサーバーが書けたりする。このライブラリは(paella)の基盤になっていたりするので、個人的に書くWebアプリは意識の外側にくらいの位置ではあるが使われていることになる。そんなライブラリ+news-reader.nlで使われているということもあってそれなりに安定していると盲信していたのだが、実はそんなことなかったという話。

ことの発端は今書いているWebアプリがある程度走るとCPUを100%使いだすというもの。これが続くと嫌だなぁと思って、モニター機能をつけてみたところ、どうも挙動が怪しい。スレッドを50個作っているのに動いているように見えるのは一つしかない。スレッドにソケットを割り当てるために持っている優先度付きキューもなぜか要素が一つしかない。

結論を言うと3つのバグが複合的に働いてCPU使用率を100%にしていた。

【バグ1】
優先度付きキューの比較ロジックがおかしかった。スレッドにソケットを割り当てるようなので、スレッドIDとそのスレッドが保持しているソケットの数をペアにして持っていたのだが、その比較がおかしく、ソケットの数が同一であれば同一の要素とみなしてしまっていた。そうすると初期化時にすべての要素が同一とみなされかつ、追加時に同一要素を削除しているので結果的に一つにしかなっていなかった。
修正はこんな感じ:https://bitbucket.org/ktakashi/sagittarius-scheme/commits/c52fab262da092a1ca676c9e067798a4c60f610f?at=default

【バグ2】
優先度付きキューに要素を足すときにサイズの取得がロック外だったため最大値を設定しているにも関わらずキューのサイズが増えていた。これ自体はCPU使用率100%に直接関係はないのだが、モニターを作ったときに予定外の値が渡されるので気付いた。
修正はこんな感じ:https://bitbucket.org/ktakashi/sagittarius-scheme/commits/a96c51bd93076ddb5454060b82cc1ed087c681f1?at=default

【バグ3】
Paellaが特定の場合にソケットを閉じていなかった。データ読み取りすると空データを返すソケットを閉じていなかった。これが無限ループを起こしてCPU使用率100%になっていた。Linux上でのみ起きるので気付きにくかったというのはある(言い訳)
修正はソケットを閉じるだけ。

実用に耐えているからといってバグがないわけではないという話である。しかし、今までスレッド1個しか働いてなかったのか、ソケット自体は複数個扱えてたのが災いして気付かんかった。

2017-09-28

砂場と模型

Mockの訳が模型でもいいかは自信ない(疑似だと味気なかった)。

プログラミングをしていると、テストをどうするかというので困る時がある。例えばあるコンポーネントのテストをしたいが、それはHTTPサーバを必要とする場合とか。実際に必要となるものによっては簡易版を用意してやるとか手はあるが、ユニットテストレベルでそこまでやる気にならないこともある。そもそも、用意した簡易版の何かしらは正しく動くのかとかも気になる。

Sagittariusではいろいろ黒魔術的な何かを使えばライブラリに束縛された値を上書きすることが可能ではある。っが、これをやるとグローバルに変更されるという問題もある。テストの実行単位が常に単一であるとか、単一スレッドでしか走らないとかにしてしまえばこれだけでも問題はないのだが、数が増えるとそれがボトルネックになるのが見えているのでできれば避けたい。

っと、この辺りまでが最近まで悶々としていた問題。もとになったのは、SchemeでもMockitoみたいなのほしいなぁというもの。そこから可搬性とか考えずに、とりあえず束縛だけ一時的に変更できればなんとかできなくね?というところに至る。っで、悶々としている間になんとかなりそうだなぁと思ったので実装してみた。実装の詳細は面白くもないだろうので割愛。(sagittarius sandbox)というライブラリに実装。使い方は以下:
(import (rnrs) (sagittarius sandbox))

(define s "b")
(define (test) (string-ref s 0))
(with-sandbox
  (lambda ()
    (define-in-sandbox '(rnrs) (string-ref s i) #\a)
    (test)))
;; => #\a

;; (test)
(playground ((string-ref '(rnrs) (lambda (s i) #\a)))
  (test))
;; => #\a
コメントアウトされてるtestのコメント外すと予定と違う値が返ってくるが、既知のバグということで。理由としてはサンドボックス内で作られる束縛は指定されたライブラリのみ作用するけど、上記のtestで使われてるstring-ref(rnrs)が依存しているライブラリの一つで定義されてるので、一回サンドボックス外で実行するとGLOCに置き換わって定義されてるライブラリを直で見に行くから。VM内でGLOCに置き換える部分をもう一段ラップして元の識別子を残すようにすれば解決できるんだけど、性能への影響が怖いのとそこまで需要があるかなぁという気持ちが混じりあってとりあえず保留。性能に影響がでないうまい方法を思いついたらやることにする。

サンドボックスができれば次はモックだということでちゃちゃっと作った。以下のように使える。
(import (rnrs) (srfi :1) (sagittarius mock))

(define (test) (make-list 3 #f))
(let ((status (mock-up ((srfi :1)) 
                (test) (mock-status-of 'make-list))))
  (mock-status-arguments-list status))
;; => ((3 #f))

(mock-up ((srfi :1)) 
  (mock-it '(srfi :1) (make-list . args) '(a a))
  (make-list 3 #f))
;; => (a a)
まだAPIが荒いのでもう少し練らないととは思いつつ、テストに使えそうな感じではある。実装に綺麗い目な黒魔術(絶対にドキュメント化されないという意味で)を多用しているのは、まぁご愛敬ということで。

2017-08-21

浮動小数点とC99とSRFI-144と

Sagittarius 0.8.6でSRFI-144をサポートした。このSRFIをポータブル実装を使ってサポートするとパフォーマンス的に得るものが何もないと思いC側でサポートすることあらかじめ決めていた。ネックになるのはこのSRFIが要求しているのがC99の数学関数であることで、Sagittariusでサポートを明記しているVS2010ではC99がサポートされていない。VS2013からはサポートされているので、4年も前の環境だし上げてもいいかなぁとは思ったが、何かの間違いでこのバージョンを使っている人がソースからコンパイルしているという可能性も0ではないかなぁと思い互換レイヤを書くことにした。

互換レイヤ自体はまぁ、普通の苦労で済んだのだが、そこから先が大変だった。Ubuntu 16.04では動くがTravis上のUbuntu 12.04ではテストがこけるとか、VS2013でのCランタイムではテストがこけるとか完全に環境依存の問題に移行したのである。ちなみに嵌ったのは以下:
  • VS2013以降のtgammaはアンダーフローが起きると0.0を返すが、Linux(glibc)では-0.0が返る(たぶんどっちも仕様上はOK)
  • VS2013以降のynは第二引数が0.0だとNaNを返すが、Linux(glibc)では-inf.0が返る(POSIX見ると第二引数が0.0だとpole errorで-HUGE_VALとあるが、C99が同義かはしらない)
  • glibcの特定のバージョン(2.21以下と思われる)ではremquoとlogbが不正な値を返すことがある。(remquoについてはバグレポートを見つけたが、logbは完全に勘。下手するとeglibc固有の問題化もしれない)
  • fl-leastはDBL_TRUE_MIN(C11)が割り当てられるので、どのバージョンのVSがサポートしてるか不明
とにかく環境がないということの方が辛く、おとなしくポータブル実装を使っておけばよかったという気持ちに何度もさせられた。また、参照実装に付属しているテストが要求する誤差が結構厳しく、適当な実装だと誤差が大きすぎるというのも苦労した(Windows)。

苦労の甲斐があるかはわからないが、Sagittarius上で浮動小数点を扱う際はこのSRFIを使うとCと同等の速度が得られることだけは保証されるようになった。っが、個人的に浮動小数点はあまり使わないので、自分では有難みを享受できないという悲しい話もあったりなかったりする。

2017-07-12

オランダでの収入と支出

ITエンジニアと給料では給料だけにしか触れなかったが、この記事によるとアメリカの一部地域(例:シリコンバレー)では生活コストも高いので世帯年収1200万以下は貧民層となるらしい。生活コストも含めた比較となるとオランダくらいしかできないので、ざっくりとオランダでの生活コストを調べてみた。

生活コスト
日用品等のコストは「Cost of Living in Netherlands」のページが詳しい。基本的には食品はそれなりに安く、家賃は高いという感じらしい。
ざっくりとしたコストとしては「What is the average cost of living in The Netherlands」のページに書いてある。以下は適当な日本語訳したリスト
  • 家賃: €800-1000
  • 電気、水道等: €150
  • インターネット(大抵テレビと電話もついてくる):€30−50
  • 健康保険:€270(3x90 18歳以下の子供は無料)
  • その他保険: €30
  • 交通費: €100
  • 食費:€100週 (€400月)
合わせると€1780−2000くらい。これに交際費等が入ってくるが、感覚的に妥当な数字かもう少しかかるかなぁというところ(上記だと最低限くらいしかない感じ)。

収入
2016年における一人あたりの手取りの平均収入は€2158となっている(参考: Average Salary in European Union 2016)。平均世帯収入は単純に2倍すればいいだろうか?

以下は2017年の額面における手取り額(日本語ただしいか?)
月収(額面)月収(手取り)年収額面
2000169525920
3000222838880
4000273651840
5000324464800
6000372677760
7000417090720
80004614103680
90005058116640
100005502129600
参考:Dutch Income Tax Calculator
年収の算出は月収x12.96になっている(注:オランダでは月8%の休暇手当が義務付けられている)。もちろんボーナスのでる会社もあるので、この年収は月収に対しての最低保証額ということになる。

€2000(上記の生活コスト)+€1000(ある程度の交際費と貯金)くらいを文化的な生活とすると、世帯収入的には年€50000くらいあれば「中の中」くらいだろうか?累進課税がキツ目なので、収入が一人だと年€61000くらいないと厳しい感じである。

現在位置ユーロ130円なので、世帯収入650万円(一人なら793万円)で「中の中」くらいの生活ができるとすれば、アメリカの1200万円で「中の下」と比べるとましなのかね?ただ、年収€61000を新卒(エントリーレベル)で出す会社は今のところオランダでは見たことないので(というか、これくらいだと既にシニアレベル)、やはり給与面ではオランダはアメリカに比べると塩っぱい気がする。少なくともIT産業に於いては。

2017-07-03

引っ越し

7年住んだアパートからの引っ越しが完了した。新居の準備がまだ全部終わっていないが(床のフローリングが一部終了してない等)今週中には終わるだろう。7年も住んでいると普段は気にしなくてもこういう時に物であふれていたんだなぁと気付かされた。引越し業者が荷物の運び出しを完了した後で10箱以上自力で運びだしたりしていた(箱詰めが失敗したとも言えなくないが、細々したものというのは往々にして忘れられがちなのだ)。

オランダのアパートは入る時も出るときも割と面倒である。入るときはだいたい床はコンクリートむき出しの状態、壁紙はあったりなかったり。出るときは以下の状態にして出ろと言われる:
  • 床はコンクリートむき出し
  • 壁は白く塗ってあること
  • 天井も白く塗ってあること
  • 壁に開けた穴は埋めること
まぁ、入った時と同じにしろと言われる。ただ、僕の場合は多少特殊で、入った時は「天井が白ければよい」という条件だったんだけど、途中で大家が変わったので「壁も白くしろ」が追加された。なので、受け取った時は青い壁とか、トイレに模様とかあったんだけど、それらを全て白く塗りつぶせという話になった。納得が行かないが、まぁしょうがない。

偶然にも、新しい居住者が入れ替わりで入ることになりかつその人がフローリング、冷蔵庫、洗濯機、オーブン、ベッドフレームを引き取ると言ったのでそれらの運び出し及び廃棄をする必要がなくなったのは幸運だったのだろう。その人にとってもそれらが無料で手に入るのは悪くない条件だと思う。多少汚れてたりしても…(余談だが、フローリングはアパートが広いこともあって総額で2000ユーロ以上かかってたりする。)

新居の鍵の受け渡しから退去までが一週間しかなく、その間に荷出しとかもあったので、非常に疲れる週であった。連日23時くらいまで運び出しと清掃等を行っていたのだが、22時くらいまでは明るいという非常に幸運な時期に引っ越ししたとも言える。これが冬だったら暗闇の中いろいろやることになっていた。

どうでもいいのだが、敷金が帰ってくるまでに2ヶ月かかるってどういうことなんだろう?どう考えても時間かけ過ぎだと思うだが?

2017-06-20

Kotlin 始めました

2週間前にこんなツイートをした。


このツイートの後えらくだるだるなスプリントを過ごしたので(1スプリント=2週間)、しばらく触っていなかったのだが、今週のプランニングでメンバーから陽に「お前はKotlin使うよな?」と煽られたのでまじめに使い始めた。

書き始めて今日で4日目くらいだけど、Javaと比較してみたりする

【長所】
  • 記述量が減る。無駄なゲッターとかセッター要らない
  • デフォルトでLambda式が使える。(Java8な環境なら関係ないけど)
  • 型推論は良いものだ
  • クラスを別ファイルにしなくてもよいのは便利
  • パッケージ定数とかも便利
  • Javaとの親和性が高い
【短所】
  • 重い。IntelliJが頻繁に固まる
  • Mavenの記述が面倒
  • 素ではMockitoとの相性が悪い(mockito_kotlinで凌ぐ)
  • Javaとの親和性が高いけど、ところどころコンパイル結果を気にする必要がある。(慣れかな)
  • inlineの挙動。混乱するだろ普通…
  • データクラスあるけど、パターンマッチない
  • デフォルトpublic。デフォルトfinalクラス。(好みの問題) 
  • Companionは面倒
Null安全は便利だけど、猫も杓子もNull安全という風潮はだいぶ疑問。まだ使ってない機能がいくつかあるけど、使う時が来たら使う感じかなぁ(Type safe buildersとか使いたいけど、使う場面があんまりないんだよなぁ…)

感想としてはJava++として使うのであれば優秀。 Kotlin的な書き方(チュートリアルにあるようなのだと信じてる)をすれば記述量がだいぶ減る(でもIntelliJが固まるので作業時間的にはトントンというのもある…)。なんだかんだで既存のJavaライブラリがそのまま使えるのはやはりうれしい。

リストとかマップとかのリテラル表記とかあったら便利だろうなぁとか、パターンマッチほしいなぁとか、なんで明示的にreturn書くんだろうとかいろいろ思うけど、今のところはJavaより楽に書けるというメリットの方が大きい感じではある。

2017-06-16

ITエンジニアと給料

Twitterで米国で働くといい給料がもらえる云々の呟きを見た。米国におけるITエンジニアの給料が破格に高いのはまぁ周知の事実として、正確にどれくらいの差があるのかというのはあんまり考えたことがなかった。以前Amazonからもらったオファーは米国なら13万ドル、ルクセンブルグなら7万6千ユーロだったので、単純に2倍弱くらい離れてるのかなぁと思っていた。(正直どうして蹴ってしまったんだと今でもたまに悔やむが、トランプ政権とか見ると行かなくて正解だったのかなぁとも思っている。)

例が一つというものどうかなぁと思ったので、欧州と米国の関数型言語求人に特化したサイトを覗いてちょっと比較してみた(ずいぶん前に登録してた)。
LevelUSEU
Senior$150k-200k€60-75k
Full stack$100k-150k£45k - £60k
Junior$120k£35k - £45k
フルスタックがシニア以下とか、通貨が違うとかはまぁ置いておいて、ぱっと見2倍以上の差はあるのかなぁと。(米国のジュニアはプログラマではないので微妙)。

上記のEUはドイツか英国なんだけど、英国は一応最大で£120kの募集要項もあったので、探せばなくはないかなぁ。

ザクッと要求するスキルを見るとだいたい同レベルのことを求めているので、やれることが同じなら米国の方が2倍くらい給料がいいということにはなる。

物価とか保険とか税金とかどれくらい生活コストがかかるのかは知らないけど、単純に見れば英語ができてチャンスがあるのであれば現状欧州出て米国に行った方がよい給料がもらえる。個人的に気になるのは、欧州はいくらか世界規模のサービス展開している企業があるのに(僕の前職もそう)給与水準は低く抑えられているという点と、ITエンジニアはかなりの奪い合いなんだけどそれに見合った報酬という感じはしないところかな。前にも書いた気がするけど、ヘッドハンターに現状より年間で5千ユーロは高くないと嫌だというと説教食らうところとか(これはオランダだけかもしれんけど)。

いろいろ書いたけど、欧州もそれなりにしょっぱい感じです。オランダ限定なら間違いなくしょっぱいです。

2017-05-19

ちょっとしたジレンマ

仕事でスクラムをやっているのだが、Grooming(最近だとRefinement)、Wikipediaの日本語ページに訳がなかったので英語のままで書くことにする、に微妙に温度差があって多少困っている。
ちなみに、スクラムのプロセスについて書くということはないので、その辺を期待しているのであれば期待はずれになると思われる。

チームでは最近縦のスライスを意識してやることにしている。そうするとどうしても最初はプロトタイプ的なものがチケットになる。このプロトタイプが結構曲者で、今のチームは横のスライスを意識してやってきた経験が長いので、プロトタイプで必要になるコンポーネントがどれくらいに複雑になるかがある程度見えてしまう。というか、開発者であれば、経験上最終的に一つのコンポーネントがどれくらいの機能が必要かが見えるので、それを考慮に入れてしまう感じである。あまりうまく例えられないのだが、レゴで城を作ればいいのに、実際のレンガで城を作ることを考える感じだろうか?

例えば簡単なSMS認証のWebサービスを作るとする。以下がチケットの詳細とAcceptance Criteria(これの訳も知らない):
詳細
ユーザからの携帯番号を受け取り、認証コードを受け取った携帯に送る。ユーザーにリクエストIDとステータスを返す。ユーザーはSMSで送られた認証コードとリクエストIDをサーバに送る。認証コードが一致すればリクエストIDと成功を返す。一致しなければリクエストIDと不一致を返す。なおUIは考えなくてもよい。

Acceptance Criteria
  • SMSを送るには以下のAPIを使う(3rdパーティーAPI)
  • リクエストはデータベースに保存する
  • デモ可能である
後はテスト項目があるけど、それは割愛。

僕はこれに対してPoC(Proof of Concept)でありかつ次のスプリントで改善して行けばいいということを念頭に最短かつ最も単純にやるという方針で5ポイントをつけた。実際JEE開発したことがある人であれば、使うフレームワークにもよるだろうが、この程度1周間もあればできると思うだろう。(ストーリポイントを時間で図るのはいかがかとは思うが、個人的には便利かなぁと思うので一週間=5ポイントにしている。)想定した工程は以下
  • 2つテーブルを作る
  • 3rdパーティAPI用ライブラリを作る
  • REST APIを2つ作る
  • ざっくばらんなMaven処理(モジュール作成等)
フルスクラッチなので、コードの記述量は多いがそれ以外は特に複雑なものはないと判断した。

っが、他のメンバーは13ポイントをつけた。ちなみに今のチームでは13ポイントは1スプリント(ちなみに今のチームでは1スプリント=2週間)ではできないとしている。その理由は:
  • テーブルデザインがいる
  • 3rdパーティAPI用ライブラリのデザインがいる
  • REST APIのデザインと他チームとの強調がいる
  • デプロイ用のサーバ等環境構築
完全にリファクタリングによる手戻りを極力減らそうという感じであった。そうすると確かにきちんとしたデザインとかあるし、それらには時間がかかるのも判る。っが、PoCでやることではない気がとも。あるメンバーはどう考えても1スプリントではできないと言い張ったし…

結局間をとって8ポイントにした。言い出しっぺの法則的に僕がやるということになったが、実際に完了までに1週間(うち1日は病欠したので、正味4日)。自分のスキルレベルをよく把握してるなぁと感心するレベルでの見積もりの正確さであった。

何がジレンマかというか
  1. 見積もりに大幅な開きがある
  2. 他のメンバーは城をレンガで建てようとする(必要以上にかっちり作りたがる)
の2つである。正直どうすればいいのかよく分からない…

2017-04-26

文字列とコーデック

R6RSに於いてポートはバイナリと文字列を明確に区別している。例えば、バイナリポートに対して文字列の書き込みはできない。この2つの橋渡し役がトランスコーダになる。トランスコーダはコーデックを受け取り生成され、transcoded-port等の手続きでバイナリポートを文字列ポートに変換する。ここまでは特に問題ないだろう。

さて、ここからが問題である。以下のコードは何を出力するだろうか?
(display "\xFF;\xD8;")
期待する挙動としては"\xFF;\xD8;"がそのまま出力される、つまり0xFF 0xD8として2バイト出力されることを期待するだろうか?

上記の挙動を期待した人は手をあげなさい。
(・ω・)ノシ
手を上げた人のそのまま残りなさい、補習があります。挙げなかった人はこのまま帰ってもよいです。もちろん補習を受けてもよいですよ。

さて、実際の挙動を見てみよう。大抵の処理系では出力される文字列は"ÿØ"となり、これのバイナリ表現はUTF-8で0xC3 0xBF 0xC3 0x98になるだろう。勘がいい方は気づいたかもしれないが、この挙動の正体はトランスコーダの仕業である。displayに出力ポートを指定しなかった場合current-output-portが使われるのは周知のことであると思われる。current-output-portにはどんな文字列ポートが割り当てられているのだろうか?R6RSによると以下である。
These return default textual ports for regular output and error output. Normally, these default ports are associated with standard output, and standard error, respectively. (omit) A port returned by one of these procedures may or may not have an associated transcoder; if it does, the transcoder is implementation-dependent.
要約:規定の出力ポート。通常は標準出力に割り当てられる。返されるポートにはトランスコーダが紐つけられているかもしれない。もしそうならそれは処理系依存である
処理系依存である。例えばSagittariusでは(native-transcoder)が割り当てられるし、Chezはトランスコーダを割り当てていない。

処理系依存の挙動ではいまいち納得が行かないので、これを処理系非依存の挙動で書いてみる。
(call-with-bytevector-output-port
 (lambda (out) (put-string out "\xFF;\xD8;"))
 (make-transcoder (utf-8-codec)))
このコードを実行すると上記と同様の出力が得られる。文字#\xFF#\ÿなるのかというのはUCS4とUTF-8の変換表を見てもらいたい。

ではどうすれば変換せずに出力できるのか?答えは割と簡単でlatin-1-codecを使うと良い。上記のコードを以下のように書き直すと予定通りに動く:
(call-with-bytevector-output-port
 (lambda (out) (put-string out "\xFF;\xD8;"))
 (make-transcoder (latin-1-codec)))
もちろん、文字列の中に多バイト文字が混じっていた場合はエラーになるので気をつける必要があるが。

余談ではあるが、この問題を回避するポータブルな方法はR7RSにはない。つまり、文字列をバイナリ表現として扱う非処理系依存なコードは現状のR7RSでは書けないということになる。また、少なくともChibiとGaucheでは文字列"\xFF;\xD8;"displayで出力したら"ÿØ"が出力された。R7RS-largeに期待したい類の問題である。

2017-03-10

JSONユーティリティ

最近の動向として猫も杓子もJSONとなっている感じがあるが、SagittariusではJSONのサポートが薄い(Githubに拙作のJSON Toolsを置いているが本体に入れようかなぁ)ので多少手厚くしようかなぁと思いSchemeオブジェクトに変換するライブラリを書いたりしてみた。まぁ、将来的にJWTとか実装しようと思うと生のデータは扱いづらいがDSLクエリーでは効率が悪いという話もあった。

以下のように使える
(import (rnrs) (text json object-builder))

;; JSON string
(define json-string "{
  \"Image\": {
    \"Width\":  800,
    \"Height\": 600,
    \"Title\":  \"View from 15th Floor\",
    \"Thumbnail\": {
      \"Url\":    \"http://www.example.com/image/481989943\",
      \"Height\": 125,
      \"Width\":  100
  },
    \"Animated\" : false,
    \"IDs\": [116, 943, 234, 38793]
  }
}")

;; records represent JSON object
(define-record-type image-holder
  (fields image))
(define-record-type image
  (fields width height title thumbnail animated ids))
(define-record-type thumbnail
  (fields url height width))

;; JSON -> Scheme object definition
(define builder (json-object-builder
                 (make-image-holder
                  ("Image"
                   (make-image
                    "Width"
                    "Height"
                    "Title"
                    ("Thumbnail"
                     (make-thumbnail
                      "Url"
                      "Height"
                      "Width"))
                    "Animated"
                    ("IDs" (@ list)))))))

;; Scheme object -> JSON definition
(define serializer (json-object-serializer
                    (("Image" image-holder-image
                      (("Width" image-width)
                       ("Height" image-height)
                       ("Title" image-title)
                       ("Thumbnail" image-thumbnail
                        (("Url" thumbnail-url)
                         ("Height" thumbnail-height)
                         ("Width" thumbnail-width)))
                       ("Animated" image-animated)
                       ("IDs" image-ids (->)))))))

(let ((image (json-string->object json-string builder)))
  ;; do some useful thing with image

  ;; ok I want JSON string
  (object->json-string image serializer))
;; Formatted for convenience
;; -> {
;;      "Image": {
;;        "Width": 800,
;;        "Height": 600,
;;        "Title": "View from 15th Floor",
;;        "Thumbnail": {
;;          "Url": "http://www.example.com/image/481989943",
;;          "Height": 125, "Width": 100
;;        },
;;        "Animated": false,
;;        "IDs": [116, 943, 234, 38793]
;;      }
;;    }
リストとかベクタとかも扱えたりするので、まぁ要りそうな機能はざっくりあるかなぁという感じ。

CLOSを使ってJavaのアノテーションよろしくゴテゴテした感じにしてもよかったんだけど、最近そういう書き方を避けてるのと、既存のレコード等も再利用可能にするためにこんな感じのデザイン。SXMLに対してのオブジェクト構築と似た感じになってるのはそっちもそんな感じのデザインで作ってあるから。

使い勝手は(当面のJSONが必要な場面がこれなので)JWTを実装しつつ見ていくことになるが、そこまで大きな変更はないだろうなぁと思ったり。

2017-03-02

Hibernateでクエリー爆発した話

JavaでORMと言えば真っ先に思い浮かぶのがHibernateであろう。データベースをほぼJava Beansのように扱える便利なライブラリである。ともすれば、裏で何が起きているのか全く感知しなくてもいいので、SQLが嫌いな人にはなかなかに受けが良いようである(要出典)

さて、裏で何が起きているのかを意識しなくていいというのは多くの場合便利な反面問題が起きた際の検知または解決が遅れるということでもある。データベースアクセスというのは大体の場合物理ファイルへのアクセスがあり、クエリの実行にはソケットが使われるので通信が発生する。これらはパフォーマンスを大きく損なう操作でもあり、一般的(誰?)は可能な限り避けるべきとされている(要出典)。ここではHibernateによって隠されたこれらの操作が引き起こすパフォーマンス劣化の体験談を今後の戒めとして記録しておく。

問題になったのはだいたいこんな感じのテーブル。
                       +--------------+
   +--------+        |  X_User_Dep  |    +-------------+          +-----------+
   |  User  |          +--------------+           |  X_UD_Prod  |          |  Product  |
   +--------+ 1   1..* |  + ID        | 1    1..* +-------------+          +-----------+
   | + ID   | o------o |  + User_ID   | o-------o |  + UD_ID    | 1..*   1 |  + ID     |
   | + Name |          |  + Dep_ID    |         |  + Prod_ID  | o------o |  + Name   |
   +--------+        +--------------+    +-------------+          +-----------+
                        o 1..*
           |
           |
                 o 1
                       +--------------+
                       |  Department  |
                       +--------------+
                       |  + ID        |
                       |  + Name      |
                       +--------------+
Java側はこんな感じのエンティティ
@Entity
@Table(name = "User")
public class User {
    @Id
    private int id;
    @Column(name="Name")
    private String name;
    @OneToMany(mappedBy = "user")
    private Set<UserDepartment> userDepartments;
}

@Entity
@Table(name = "Department")
public class Department {
    @Id
    private int id;
    @Column(name="Name")
    private String name;
    @OneToMany(mappedBy = "department")
    private Set<UserDepartment> userDepartments;
}

@Entity
@Table(name = "Product")
public class Procdut {
    @Id
    private int id;
    @Column(name="Name")
    private String name;
}

@Entity
@Table(name = "X_User_Dep")
public class UserDepartment {
    @Id
    private int id;
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "User_ID")
    private User user;
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "Dep_ID")
    private Department department;
    @OneToMany(mappedBy = "product")
    private Set<Product> products;
}

@Entity
@Table(name = "X_UD_Prod")
public class UserProduct {
    @Id
    private int id;
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "UD_ID")
    private UserDepartment;
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "Prod_ID")
    private Product product;
}
ビジネスロジックは以下のようなことを実行する:
  • ユーザAが所属する部署に所属する全てのユーザが保持するプロダクトを得る
  • 適切なオブジェクトに変換し返す
普通に考えれば、まず条件を満たす全てのレコードを取得し変換処理をするだろう。僕が目にしたコードは以下のようなことをしていた。
  • ユーザAの所属する部署を得る
  • 上記の部署に所属する全てのユーザを得る
  • 上記で得られたユーザ毎にプロダクトを取得し、変換する
SQLが直接見えるのであればこの処理がO(n*m)かかるひどいものだとすぐに気づくのだが、Javaのコードを見ると大体以下のように実装されていた。

getAllUserInDepartment(thisUser.getDepartment()).stream()
    .map(UserDepartment::getProducts)
    .map(convert)
    .collect(Collectors.toList);
これの困ったところは、最初のgetAllUserInDepartment以外は目に見えたデータベースアクセスがないということ。実際にはproductsはLAZYに初期化されているので、convertないで他の何らかProductのプロパティにアクセスして初めて取得のクエリが走る。EAGERに取得しろよという話もあるが、このオブジェクトが使われているのはここだけではないので影響範囲に責任持ちたくないという無責任さからやめた。キャッシュという選択肢もあったんだけど、使われているデータベースへのアクセスがJavaアプリケーション以外からもあるので多分キャッシュの整合性が取れないということ(+僕自身Hibernateにそこまで精通していないの)で断念。

どうしたかといえば、エンティティ定義は変えずに、ひたすら下請けのSQLがどんな風になるかを想像しながらDetachedCriteriaを書いて逃げた。正直、SQL直接書かせてください、お願いしますという気分にはなったが…こういう(キャッシュ使えない、エンティティ定義変更できない)時はどうするのがベストプラクティスなのか興味があるが、僕のググり力の低さのせいで解決方法は見つからず。

Hibernate便利なんだけどある程度SQLが書けると隠しすぎてて辛いという時があるという話。

2017-02-09

楕円曲線暗号

今年の抱負の一つ、楕円曲線暗号を実装している。とりあえず肝の一つであるECDSAを実装し終えた。こんな感じで使える。
(import (rnrs) (crypto))

(define keypair (generate-key-pair ECDSA :ec-parameter NIST-P-521))

(define msg "this message requires digital signature")

(define ec-signer (make-cipher ECDSA (keypair-private keypair)))

(define signature (cipher-signature ec-signer (string->utf8 msg)))

(define ec-verifier (make-cipher ECDSA (keypair-public keypair)))

(cipher-verify ec-verifier (string->utf8 msg) signature)
;; -> #t
一応NISTが推奨する楕円曲線パラメータは全部実装してある。テストベクタもあるので、当然テストもしてある。おかげでテスト時間が増大した。処理が重い…SECGが推奨するパラメタも実装しないとなぁと思いつつ割と現状で満足している感もあり、既に随時追加する方向にシフトしつつある。

今となっては笑い話だが、実装している間で一番苦労したのが「正式な仕様を見つけること」だったりする。暗号系に限らず、プロトコルの実装をする際は可能な限り「正式な仕様」(RFCとか)を当たるようにしているのだが、楕円曲線暗号はこれを見つけるのに苦労した。Google先生にお伺いを立てると大抵RFCに当たるんだけど、探した限りだとRFCにはECDSAの拡張はあってもそれ自体がない。まさかWikipediaに書いてあるのをそのまま(実際正しかったんだけど)鵜呑みにするのもなぁと思い探したら、行き着いた先はANSIだったという。最終的にはX9.62でググるのが正解というのに辿り着いた。こういうの知らんと探せんなぁと思った次第。

実はこれを実装してようやくスタートラインに立ったというのが正直なところ。ここからECDH、SSHとTLSにECDSA+ECDHを追加していく予定。まだ先は長いが、今年の抱負なので、今年中に終わればいいだろうくらいな気持ちでいたりはする。

2017-02-01

ひらけ!ポンキッキ

r/lisp_jaとTwitterに以下の投稿があった。
前者がGuileで後者はR6RSで実装されている。文字列をグルグルさせるのならSRFI-13のxsubstringが使えるだろう思い、僕も書いてみた。
(import (rnrs) (srfi :13))

(define s "ひらけ!ポンキッキ")

(define-syntax do-while
  (syntax-rules ()
    ((_ ((var init ...) ...) (pred r) commands ...)
     (do ((first #t #f) (var init ...) ...)
         ((and (not first) pred) r)
       commands ...))))

(do-while ((t s (xsubstring t 1))) ((string=? s t) #t) (display t) (newline))
Cのdo ... whileを真似たdo-whileマクロは正直いらんけど…
以下は実行結果
$ sash hirake.scm
ひらけ!ポンキッキ
らけ!ポンキッキひ
け!ポンキッキひら
!ポンキッキひらけ
ポンキッキひらけ!
ンキッキひらけ!ポ
キッキひらけ!ポン
ッキひらけ!ポンキ
キひらけ!ポンキッ
毎回文字列の比較をするので、当然効率は良くないが、まぁこういうこともできるということで。

2017-01-31

一移民として

オランダに移住してそろそろ8年になる。移民の定義的(Wikipediaが正しいかは知らんが)には移民で問題ないだろう。

大統領令

さて、一移民として最近ニュースサイトから目が離せないでいる。もちろん今を賑わす時の人、第45代アメリカ大統領ドナルド・トランプ氏関係のニュースである。先日あった特定7カ国籍を持つ人のアメリカ入国拒否には大きな衝撃を与えられた。
なぜこのニュースが大きな衝撃になるのか疑問に思うかもしれない。ニュースサイトの論調はともかくとして、傍目から見ればテロリストの抑止にも見えなくない(それにしても、ビザを持っているのに入国できないという事実があったことには目を瞑る必要はあるのだが…)。一移民の視点、少なくとも僕個人の視点、から見ればこれは移民排斥の第一歩に写った。

トランプ氏は就任式の際に「アメリカ第一」と唱えている。
それと同時に大統領選挙の際のスピーチにいくつか人種差別的な発言もある。
これらのニュースから導き出された僕個人が描くトランプ像は白人アメリカ主義者というものになっている。

この「アメリカ第一」と個人的なトランプ像から、先日の大統領令はある種の試金石的な位置づけにあるのではないかと思っている。つまり、テロリスト排除という錦の御旗を掲げることでどれくらい潜在的な人種または宗教差別を隠せるか。そこから発展させて最終的には白人主義に持っていく道筋を建てようとしたのではないか。

ここまで来ると偏執病ではないかと思わなくもないが、過去にナチが存在したという事実もある。あまり考えたくないが歴史は繰り返されるものであるのであれば、ナチズムが再び起きることもありえなくない。

対岸の火事?

事件はアメリカで起きているのだ、オランダに住む僕にはあまり関係ないのではないか?と思わなくもない。っが、意外にも周りのオランダ人(国籍的に、人種的には違う)的にはトランプの大統領令を歓迎する人もいる。難民に関して言えば、ヨーロッパも難民問題に悩まされている。隣国のドイツからは難民関係の事件が絶え間なく流れてくる。
また、割と多数(少なくとも僕の周り)のオランダ人は「中東からくるイスラム系移民は全てテロリスト」と誇張を含むとはいえそれなりに真剣に言っている。

中東移民全テロリスト発言も井戸端会議で話されている程度であればまだ可愛げもあるかもしれない。しかし、それを掲げる政治家がいるとなれば話は多少違ってくる。

Geert Wildersはオランダの反イスラム主義政治家である。現状のところ反イスラム主義だけではあるが、いつ移民排斥になるかは検討がつかない。実際、彼はヨーロッパの難民受け入れ体制に反対している。(もっとも難民の多くはイスラム系なので難民の受け入れに反対なのかは判断が難しいところではあるが…)
また、彼が率いるPVV(Partij Voor de Vrijheid、訳:自由党)は2009年に議席数を150議席中32議席と大きく伸ばしている。(この年はちょうどオランダに来た年で、極右の政党が大幅に議席数を伸ばしたこのニュースはオランダに住むことを不安にさせられた。) 議席を伸ばしたということは、少なくない数のオランダ人が彼の政策に賛同しているということである。それが、反イスラム主義なのか、別の政策に大してなのかはわからないが、賛同者にとって反イスラム主義は問題にならないとも言える。

まとめ

自国を離れていると、こういうニュースには常に戦慄させられる。いつか自分がその対象になる可能性があるからだ。トランプ大統領政権下で何が起きるのか見てみたいという好奇心と、とっとと彼を引きずり下ろして心に平穏を与えてほしいという相反する2つの感情がせめぎ合っている気がする。

2017-01-22

R7RS-largeサポート

本当は日本語リリースノート的なのにするつもりだったのだが、あまりにも眠くてリリース作業だけして寝てしまったという…

Sagittariusは0.8.0からR7RS-largeのRedEditionをサポートするようになった。具体的には以下のライブラリが使用可能になる。
  • (scheme list) - SRFI-1のエイリアス
  • (scheme vector) - SRFI-133のエイリアス
  • (scheme sort) - SRFI-132のエイリアス
  • (scheme set) - SRFI-113のエイリアス
  • (scheme charset) -  SRFI-14のエイリアス 
  • (scheme hash-table) - SRFI-125のエイリアス
  • (scheme ilist) - SRFI-116のエイリアス
  • (scheme rlist) -  SRFI-101の手続きをリネーム
  • (scheme ideque) - SRFI-134のエイリアス 
  • (scheme text) -  SRFI-135のエイリアス
  • (scheme generator) -  SRFI-121のエイリアス 
  • (scheme lseq) - SRFI-127のエイリアス
  • (scheme stream) -  SRFI-41のエイリアス
  • (scheme box) -  SRFI-111のエイリアス 
  • (scheme list-queue) - SRFI-117のエイリアス
  • (scheme ephemeron) -  SRFI-124のエイリアス
  • (scheme comparator) -  SRFI-128のエイリアス
ライブラリ名等がR7RSのWikiにこそっと修正されて上がっていた。個人的にこういうのはどこかに投げてほしい、c.l.sとか。でないとマジで見落とす…

注意するところとして、
  • (scheme ilist)で作られる不変リストは通常のcar等では扱えない
  • (scheme rlist)で作られるランダムリストは、同上
  • (scheme ephemeron)は厳密にはephemeronではない(が仕様は満たしている)
くらいだろうか。

RedEditionだと単に便利ライブラリが標準に追加されたくらいの感覚しかないが、それでもR7RS-largeをフルサポートしている処理系は現状ではSagittariusだけではないだろうか。

そういえば、その昔R7RS-largeに(scheme inquery)というライブラリが追加されたことがあるのだが、これって正式に仕様になってるのかな?SRFI-112とかWG2とか見ても見つからないから、ライブラリ名は先走りだったかな?

2017-01-02

謹賀新年

年末に2016年のことを振り返る余裕がなかったので、新年の豊富とともに振り返ってみんとする。

2016年を振り返る
個人的にいろいろ激動な感があった(感があっただけで激動はしていないが) 。Amazonのオファーをキャンセルしたり、転職したり。Scheme Workshop 2016にも行ったなぁ。10月以降は現職での仕事が忙しかったのであまり何もないけど、Schemeで書いたサービス(と呼べるほどでもないが)を立ち上げたりしたか。

忙しいのと反比例してSagittariusの開発は少し停滞していた感がある。 適当にSRFIを追加した以外は特に目新しい機能もなく、といった感じである。忙しくても身は一つなので割ける時間は減るといった当たり前のことを痛感した年でもあった。

筋トレをすると言ったのだが、蓋を開けてみると志半ばで挫折した感がある。年の後半は特に時間が割けなかった。

2017年の豊富
酉年だから飛躍の年、とか言うつもりはないが、以下のことを通年でしようかなぁと
  • 筋トレ。月水金くらいで30分以上くらい自重トレ。行けたらジムにも行く。
  • ギターの練習。週末くらいで
  • 17時退勤。仕事は二の次くらいの勢いで
  • 本を読む。月一冊くらいは読みたいところ
Sagittarius的には以下をなんとかしたいと思っている
  • OAuth
  • 楕円曲線暗号(RFC6090)
  • R7RS-large対応
  • 日本語ドキュメント
最初の2つは当面という感じだが、下2つはちょいちょいやっていく感じかな。どうせ何かしら見つけて作っていくとは思うけど。

基本的には、なんとかなる、ゆるーくまったり、くらいの気持ちでいこうかなぁと思っている。ということで、今年もよろしくお願いしますm(_ _)m