標高+1m

Don't be rational.

biwascheme call/cc 非同期処理と大域脱出

引き続きbiwaschemeで呪文を唱えております。

;;treasure hunt
(let ((data (<o> 'data (fetch-json "treasure-map.json"))))
  (begin 
    (listen-click "button")
    (console-log (<o> 'treasure (fetch-json (<o> 'treasure-url data))))))

#0: 宝探し

call/ccで非同期処理を書くと、あらゆるところから処理が湧き出して流れていく、不思議なコードが書ける。 書けるのは良いが、実行すると、最初にcall/cc自体の値が継続の流れの中で引っかかってしまう。

(define (fetch-json%% url)
  (call/cc (lambda (k)
    (ajaxy-fetchy-thing (lambda (data) (k data)))))

(define (listen-click%% sel)
  (call/cc (lambda (k) (add-handler! sel "click" k))))

#1: 疑似コード

つまり、非同期リクエストのレスポンスを流したい川に、
まず最初に(call/cc (lambda (k) ...))自体の評価値(i.e. lambdaの値)が流れて行ってしまう。

そこで、lambdaの評価時はコールスタックを吹き飛ばしてしまって、継続をスキップしよう。

(define (fetch-json% url)
  (call/cc (lambda (k)
    (ajaxy-fetchy-thing (lambda (data) (k data)))
    (raise "Let's blow away that bustard stack frame")))

(define (listen-click% sel)
  (call/cc (lambda (k) 
    (add-handler! sel "click" k)
    (raise "Let's blow away that bustard stack frame"))))

#2: 例外による大域脱出

うまく動くがこれでは少し荒っぽすぎるし、うるさい。

継続がない継続を使えば、例外を起こさず安全にスタックを消し去れる。 こういうのを大域脱出という。

(define idle #f)

(call/cc (lambda (k) (set! idle k)))

(define (fetch-json url)
  (call/cc (lambda (k)
    (ajaxy-fetchy-thing (lambda (data) (k data)))
    (idle)))

(define (listen-click sel)
  (call/cc 
    (lambda (k) 
      (add-handler! sel "click" k)
      (idle))))

#3: 継続による大域脱出

なるほど。さすがはcall/cc、制御フローのスイスアーミーナイフ。

コード中の主要な未定義関数はこちら: https://gist.github.com/ympbyc/dfc0c72956f1cecc32cd643486017a71

集中用設定

thinkpad x201 in concentration mode

X設定

画面に琥珀色のティントをかける。

xrandr --output LVDS1 --gamma 1:0.7:0.1

--output は xrandr -q で探す.

Firefox設定

about:config

動画を無効化

media.mp4.enabled = false
media.webm.enabled = false

サードパーティ画像をブロック

permissions.default.image = 3

Dark Modeアドオン

https://addons.mozilla.org/ja/firefox/addon/dark-mode-webextension/

call/ccの合成の解

compose-c/cc

やりたかったのはこういうことでした。

たまに便利なことがあると思う。

(define (compose-c/cc . fs)
  (letrec ((vals (list->vector
                  (map (^ (f i)
                          (f (lambda (res)
                               (vector-set! vals i res)
                               (when cont (cont)))))
                             fs
                             (iota (length fs)))))
           (cont #f))
    (call/cc (lambda (k) (set! cont k)))
    (vector->list vals)))

(console-log (apply string-append
                 (compose-c/cc (^ (k) (timer (^ () (k "good")) 3)
                                  "hello ")
                               (^ (k) (timer (^ () (k "bye")) 2)
                                  "world")
                               (^ (k) (timer (^ () (k " :)")) 5)
                                  "!"))))

call/ccの合成の訂正

前回の記事で色々と誤りがあったので訂正

biwaschemeのcall/ccの挙動に怪しいところがあるというのは間違いで、僕の理解が怪しかったのと、jsとのinterop周りで挙動がおかしくなっていた。 biwaschemeの継続の実装は問題ない様子。失礼しました。

もう一点、

call/ccを適用した関数内でUIに対するハンドラを書いて合成するパターンは、いろんな継続がいろんなタイミングで呼ばれてぐちゃぐちゃになるので、もう少し深く考える必要がある。

うまいやり方を発見したらまた書きます。

call/ccの合成

もうjsが書けない体になってしまったのでbiwaschemeでcall/ccとマクロを使いまくっている。 yharaさんありがとう。

www.biwascheme.org

biwaのcall/ccの挙動には怪しいところがある気がするけど細かいことは気にせずボヤっと動けば良い。

いくつかテクニックをメモ。

call/ccを非同期処理に使う

非同期IOをブロッキングしているかのように書ける。(これは昔記事にした。)

(cdr (assoc 'data (call/cc (fetch "https://???.json"))))

call/ccの合成

call/ccを複数合成できる。魔法のよう。

(define (listen-change selector)
 (w/js-cont k      ;;see gist
    (add-handler! selector "change" 
      (lambda (e) (js-call k (.. e 'target 'value))))
    ;;デフォルト値
    (js-call k (.. (qsel selector) 'value))))

(define (execute-search name address date)
  ;; ...?name=<>&address=<>&date=<>
  ;; search)

;;説明のため冗長に書いた
(execute-search 
  (call/cc (listen-change "#name"))
  (call/cc (listen-change "#address"))
  (call/cc (listen-change "#date")))

↑ リアクティブに複数のinput要素の入力を繋げて検索を投げる例

biwaschemeはjsとのinteropに落とし穴がいくつかあるのでそれを避けるクラッジをいくつかこのgistに放り込んでおいた。
BiwaScheme glue functions · GitHub

ブラウザにemacsから繋ぐと便利。 Biwascheme from Emacs (with repl) · GitHub

※いろんな継続が呼ばれてぐちゃぐちゃになることがある。

クラックリング -- パーカッシブなジャグリング

f:id:ympbyc:20160107133932j:plain
crackle balls

こんにちは、クラックラーのノリです。今日で26歳になりました。

今日は新しい遊びを発明しました。

木製の密なボールでパームジャグリングをするといい音が鳴ったので、リズムを作るようにわざと音を鳴らしてみた。

これがクラックリング:

youtu.be

ボールにアクリル絵の具を塗って、半乾きの状態でクラックリングすると、クラックルボールができる。

流行ってほしい!

パーカッシブなジャグリングには、Chuka chuksという先輩がいる。そちらも面白い。

https://www.chukachuks.com/