標高+1m

Don't be rational.

カッコの少ないSchemeを作る

f:id:ympbyc:20150908160824p:plain

昨日の記事

ympbyc.hatenablog.com

の内容をScheme (gauche)で実験できるようにしてみます。

今回の記事は、上から順にGaucheのリスナに貼り付けていけば、動作が確認できるようにしてあります。

準備

まず、固定長引数とそれ以降の引数を取って、余った引数を結果にapplyする関数を作るマクロを作ります。define-syntax面倒臭いのでdefine-macroしちゃいます。

(define-macro defix
  (lambda (defclause . body)
    `(define (,@defclause . next)
       (if (pair? next) 
           (apply (begin ,@body) next)
           (begin ,@body)))))

(macroexpand '(defix (-car x xs) x))
;;=> (define (-car x xs . next) 
;;=>   (if (pair? next) 
;;=>     (apply (begin x) next)
;;=>     (begin x)))

(define-macro lamfix
  (lambda (params . body)
    `(lambda (,@params . next)
       (if (pair? next) 
           (apply (begin ,@body) next)
           (begin ,@body)))))

(macroexpand '(lamfix (x xs) xs))
;;=> (lambda (x xs . next) (if (pair? next) (apply (begin xs) next) (begin xs)))

ちょっと汚いけどあんまり気にしないで。

以降、すべての definedefix, lambdalamfix に置き換えて定義していきます。

リスト関数

(defix (cons x xs)
  (lamfix (f) (f x xs)))

(defix (car xs)
  (xs (lamfix (y ys) y)))

(defix (cdr xs)
  (xs (lamfix (y ys) ys)))

(defix (-car x xs) x)
(defix (-cdr x xs) xs)

(defix (<: x xs)
  (lamfix (y) (cons y (cons x xs))))

(defix (list x)
  (cons x '()))

(list 4 <: 3 <: 2 <: 1 -car)           ;;=> 1
(list 4 <: 3 <: 2 <: 1 -cdr -cdr -car) ;;=> 3

mapfilter の例も同様に、 defixlamfix をうまいこと使って作っていきます。

(defix (map xs f)
  (if (null? xs) '()
    (cons (f (car xs)) (map (cdr xs) f))))

(defix (filter xs f)
  (if (null? xs) '()
    (if (f (car xs))
      (cons (car xs) (filter (cdr xs) f))
      (filter (cdr xs) f))))

(defix (prefix f)
  (lamfix (x xs) (pa$ f (cons x xs))))

(define -map (prefix map))
(define -filter (prefix filter))

(list 5 <: 4 <: 3 <: 2 <: 1 
 -filter odd? 
 -map    (pa$ * 2) 
 -map    print)
;;=> 2
;;=> 6
;;=> 10
;;=> #<closure (cons cons)>

パイプライン演算子

-> も簡単です。

(defix (-> x)
  (lamfix (f)
    (lamfix (g)
      (f (g x)))))

(defix (<- x) x)

(-> 2
 -> (pa$ + 3)
 -> (pa$ * 4)
 <- number->string)   ;;=> "20"

できました!

混ぜて使う

固定長引数の関数は defix で定義して、可変長引数の関数は define で定義すれば、混ぜて使うこともできます。

(define (list . xs)
  (fold-right (lambda (x acc) (cons x acc)) '() xs)) ;;再定義したconsを使うため

(-> (list 1 2 3 4)
 -> (cut map <> (pa$ * 2))
 <- (cut map <> print))
;;=> 2 4 6 8 #<closure (cons cons)>

まとめ

Scheme処理系の上に、マクロを使って評価規則をちょっとだけ変えたLispを実装しました。Lisp式のマクロがあると言語の(見かけ上の)評価規則すら変えられるという例です。

リストの例(consの改造)は影響が大き過ぎるので実用は難しいと思いますが、固定長引数の関数を新しく作る時にとりあえず defix を使ってみるっていうのはやってみると意外と実用的かもしれません。


オススメ

Lispから可変長引数を引き算したらできること

f:id:ympbyc:20150907225639p:plain

Schemeから可変長引数を引き算したら -- Island Life

Shiroさんが面白い記事書かれてたので、前に実際に可変長引数をなくしたLispを作って発見したことを紹介します。*1

実装者とは全く別の、遊ぶ人の視点からの記事です。

この記事では意図的にマクロを一切使わないという制約のもと、いわばラムダ計算パズルをします。

左結合のカッコを省略する

少々恣意的ですが、

((compose f g) x)

;;こう書ける
(compose f g x)

こういうこと、引数の数が固定なのでカッコを省略しても一意に評価できます。関数を返す高階関数を使うときに便利。以下の例では全てこの仕組みを存分に活用します。

list関数もクオートも使わずにリストを作る

Shiroさんの記事で言及されていたように、可変長引数がないと (list 1 2 3 4) ができなくて不便です。これも一工夫でうまいことできます。要するに1つずつ cons していけばいいって話ですが、それでは面倒なので前項の仕組みを活用します。

まず cons, car, cdrの仕組みを思い出してみます。

(define (cons x xs)
  (lambda (f) (f x xs)))

(define (car xs)
  (xs (lambda (y ys) y)))

(define (cdr xs)
  (xs (lambda (y ys) ys)))

こうですね。*2 2値にconsを適用するとクロージャに評価されます。
ここでちょっと寄り道して carcdr を少しシンプルにした -car-cdr を作ります。

(define (-car x xs) x)

(define (-cdr x xs) xs)

;;すると

(cons 1 (cons 2 '()) -cdr -car) ;;=> 2

こうやって後置のリスト関数が作れるわけですね。同じ理屈で中置バージョンのcons、 <: を作ってみます。

(define (<: x xs)
  (lambda (y) (cons y (cons x xs))))

時間がかかりましたがこれを左結合カッコの省略と組み合わせると、やりたかったことが実現できます。

(cons 1 '() <: 2 <: 3 <: 4 <: 5) ;;=> '(5 4 3 2 1)

;;おまけ

(define (list x)
  (cons x '()))

(list 5 <: 4 <: 3 <: 2 <: 1) ;;=> '(1 2 3 4 5)

まあ普通の list よりはちょっと不便ですが見た目は綺麗でしょ?

リスト関数の後置、中置化

同じように他のリスト関数も後置または中置バージョンを作ると便利です。予め引数の順番を変更したリスト関数を作っておきます。

(define (map* xs f) (map f xs))
(define (filter* xs f) (filter f xs))
;;etc

(define (prefix f)
  (lambda (x xs) (pa$ f (cons x xs))))

(define -map (prefix map*))
(define -filter (prefix filter*))
(define -take (prefix take))
;;etc

こうすると

(list 6 <: 5 <: 4 <: 3 <: 2 <: 1
 -filter even?
 -map    (pa$ * 2)
 -take   2
 -fold   + 0)      ;;=> 20

便利でしょ?

パイプライン演算子

この仕組みで中置化できるのはなにもリスト関数だけではありません。関数合成 compose を中置化してF#のパイプライン演算子 |> や、clojureのスレッドマクロ -> のような関数を作ります。例によってマクロではなくただの関数です。

(define (-> x)
  (lambda (f)
    (lambda (g)
      (f (g x)))))

(define <- identity)

(-> 2
 -> (pa$ + 3)
 -> (pa$ * 4)
 <- number->string)   ;;=> "20"

中置とは言っても最初の値をラップする仕組みのためにちょっと不思議な見た目になります。 -> で計算をつないでいって、 <- で結果を取り出します。

まとめ

  • 可変長引数を撤廃することで、左結合のカッコを省略できます。
  • するといろいろ面白いことができます。

Land of Lisp最高です。

続き: Gaucheで実験できるようにしてみました。

ympbyc.hatenablog.com

ちなみに、もうずっと触ってなくて動くかわからないんですが、実験に使ったオレオレLispはこれです。

github.com

*1:この処理系ではデフォルトのカリー化もやっていて、これを使うともっと面白いこともできるんですが今回は割愛します。

*2:実際のScheme処理系ではconsセルをクロージャで表現するということはしないと思いますがここでは忘れます。

燃え尽きプログラマと動的開発について

f:id:ympbyc:20150810204334p:plain

徳島の山奥でフロントエンドJSのための動的開発環境を作っている。関連して、会社の技術ブログでチラッと動的開発について触れた。こっちではもう少し突っ込んで書いてみる。

この記事の後半ではBirdについて触れるけれど、この記事の目的はBirdの宣伝ではなく問題提起と解決策の示唆です。一緒に開発環境について真剣に考えてみたい。

mechanic.pilotz.jp

高等言語の発明から60余年、数え切れないほどのプログラミング言語があって、みんなそれぞれ気に入った言語を使ってソフトウェアを記述しているけれど、一部の例外*1を除くと、どの言語を使っても本質的な開発スタイルは一緒なのが現状だろう。ドキュメントを参照しながらエディタないしIDEソースコードを記述し、実行して動作確認をする(テスト含む)。静的言語と動的言語の違いはソースコードの記述と実行の間にコンパイルが挟まるか否かだけだ。

これが悪いというわけじゃない。シンタックスが好きな言語なら、エディタで綺麗にハイライトされたソースを眺めてるだけで楽しいこともある。僕はRainbow Delimiterで虹色に輝くS式をPareditするだけで心が落ち着く。

でも時々、エディタと向かい合うのが辛い時がある。Joel on Software - 射撃しつつ前進で書かれているような現象で、このブログでも過去に触れた

プログラマの生産性の一番大きなファクターはその時の精神状態だ。もうこれは有無を言わさずそうなのだ。プログラミングスキルや知識やコミュニケーション能力や読解力なんかは差し置いて、ダントツで気分の問題が一番大きいのだ。管理職の方は是非参考にしてください。

話が脱線したように見えて、これがそうじゃない。気分が良い時は、お気に入りのエディタとお気に入りのキーボードでお気に入りの言語を書き殴るのが一番効率が良い。些細なデバッグに1時間や2時間かかろうとも砂糖とカフェインとニコチンで乗り切れるし、残業でも泊まりでも平気でできる。要するにハイだからだ。

でも気分が乗らない時はもうどうしようもない。エディタを開くのさえ苦痛で、画面いっぱいのソースコードなんて見た時には目は虚ろに、脳みそは粘土になって、手は勝手に⌘-tabを叩いて僕をブラウザに引き戻す。こんなときはGmailをポチポチいじったりSlackでbotをからかったりとか軽い作業しかできない。これは皿洗いとか洗濯とかと一緒で、要するに一度やり始めてしまえばどうってことはないはずなのだ。でもプログラミングはこの状態からやり始めるまでの障壁が極端に高い気がする。

だったらGmailやSlackを弄るくらいの感覚でプログラミングができれば良いんだ。

エディタで書いて、別途動作確認というループをUIとして捉えて、その問題点を考えよう。

まずレスポンスの問題がある。普通のUIなら、なにかアクションを起こしたときにアプリケーションを切り替えて最初から実行し直して結果を確認するなんてことはあり得ない。Slackで文章を書いてEnterを押したらすぐにチャンネルに表示されるし、Gmailでスレッドのタイトルをクリックしたらすぐに本文が表示される。ゲームと一緒なのだ。アクションに対する報酬は即座に欲しい。これを 課題1 とする。

次に、イントロスペクションの問題。これにドキュメントの問題も含める。実際にプログラムを書くときは、エディタ→動作確認→エディタ→動作確認という単純なループにはならず、デバッグのために実行時情報を覗き見たり、ドキュメントを参照したりといった脇道が発生する。理想的には全部一つの画面でやりたくないですか!? これが 課題2

最後に、エディタの精神衛生上の問題は、きっとその圧倒的な視覚的情報量だ。そして多くの場合、表示される情報が十分整頓されていないこともストレスの原因だろう。これを 課題3 としよう。

課題1課題2 の半分を解決するのが動的開発だ。ここで言う動的開発ってなんのこっちゃについては記事冒頭のリンク先を参照して頂きたい。簡単に言えばランタイムに開発する手法のことだ。開発環境自体が実行環境上のソフトウェアなのだ。書いた式はその場で評価して結果がわかるし、実行時情報についてはそもそもこれが実行時、つまりランタイムであるわけで、その場でなんでも覗き見れる。 課題2 の残り半分、つまりドキュメント問題は動的開発の定義の範疇ではないというだけで、動的開発環境にドキュメント参照機能をつけるのは簡単だ。

問題は 課題3 だ。これの解決には2つ必要なものがあると思う。コード分類の指針とGUIだ。

まず情報の整頓が十分でないとはどういうことか。

テキストファイルだとどうしても上下方向への1次元しかコードの各部分(コード片)を分けて配置する余地がないため、まったく違う役割のコード片がダラっと並んでしまいがちだ。加えて上下方向の次元は、純粋関数型言語でもない限り実行の順番というセマンティクスも持っているため、実行順に依存したコードなのかそうでないのかがはっきりしないという問題も抱えてしまう。

それぞれ疎なコード片は疎であることがはっきりするように並べたいわけで、これにはもう一つ以上の次元が必要になることを納得頂きたい。

コード片を分類する指針も必要だ 。冒頭のリンク先で紹介したSmalltalkでは、これをクラスカテゴリとクラスとメソッドカテゴリで分類していて、クラスブラウザを使ってナビゲートできるようになっている。

今回開発中のBirdでは違う方針を採った。だってオブジェクト指向じゃないから。

Birdを汎用の開発環境ではなく特定のFLUXフレームワーク専用にした意図はここにある。フレームワークを使うと、自然に各コード片は明確に分類できる。MVCでいえばモデルはモデルで纏めればいいし、ビューはビューで纏めればいいということだ。今回はFacebook流のFLUXを分解して、コンポーネントの概念をなくした簡素な(未圧縮2KB)フレームワークを使った。コンポーネントがないので、このフレームワーク用のコード片は

の4種類に分けられる。ちなみに関数型なのでストアはオブジェクトではなく、リードオンリーなオブジェクトへの参照(Clojureでいうatom)である。

この分類を使うと、こんなUIを作れる。

f:id:ympbyc:20150811194146p:plain

トランジションリスナの赤丸や、トランジションとDOMリスナのピルにホバーするとソースがプレビューできて、クリックすれば編集できる。一度に提示する情報が減り、圧迫感が軽減された。

コードの種類の次元が加わり、更にトランジションリスナは3次元になっている。エディタでの上下1次元の配置より格段に整頓されていることに同意してもらえると思う。

注意して欲しいのは、この記事ではグラフィカルプログラミングについて何も触れていないことだ。グラフィカルであることに主眼はない。インターフェースの改善を実直に行った結果こうなっただけ。

思ったより長くなってしまった。とにかくこれで課題は3つとも解決し、気分が乗らない燃え尽き状態でもGmailやSlackのようにプログラミングできそうな兆候が見えてきたのではないだろうか。

Birdを使った開発の様子をスクリーンキャストしてみた。お気楽な感じが出せただろうか。

www.youtube.com

Birdはまだ生焼けだけど、方向性は面白いんじゃないかと手前味噌ながら思っている。

面白い開発環境を作るのが流行ったら面白いなと思います。みなさんも如何でしょうか。

Birdを触ってみたい方はこちら

mechanic.pilotz.jp

*1:Smalltalk, データフロープログラミング, Scratchなどのグラフィカル言語, etc

神山に引っ越してきました

f:id:ympbyc:20150619113533p:plain

6/15日から、株式会社PILOTサテライトオフィス開設要員として、徳島県神山町に赴任してきました。合わせて新設した研究開発部 PILOT Proto Lab の拠点作りで慌ただしい日々を送ってます。

proto.pilotz.jp

3Dアルゴリズミックモデリングプロジェクションマッピング、VR、ドローン、ライブストリーミングなど、面白そうなものに片っ端から手を出して行こうと準備を進めています。

f:id:ympbyc:20150619114424j:plainf:id:ympbyc:20150619114431p:plainf:id:ympbyc:20150619114911j:plain

よろしくお願いします。いつでも遊びに来てください。

f:id:ympbyc:20150619114352p:plain

f:id:ympbyc:20150619162736j:plain

玲音はBeOSユーザーだった!? lainのLisp開発環境を発掘!

f:id:ympbyc:20150613140739p:plain

こんばんは。アマチュアLisp考古学者の山下です。先週弊社でピザを焼きながら唐突に話題に上った、lainのHandiNAVIにLispソースコードが表示されているシーンについて検証していきます。

幻のLisp開発環境を手に入れてコネクトワイヤードしたい!

f:id:ympbyc:20150612193455j:plain

まずは先人たちの研究によって判明している事項のまとめ:

以上のことはwikipedia英語版のSerial Experiments Lainの記事にまとまっています。

ちなみに、このライフゲーム、お好みのCommon Lispのリスナーに書けば動くんですが、ちょっと見た感じ停止しないっぽいので、カウンターつけるなり、next-cycle の頭とかに (sleep 1) くらい入れてやると良いです。

f:id:ympbyc:20150612234757p:plain

それはさておき、今回特定したいのは、Lispを表示しているこのエディタ、開発環境の正体です。

f:id:ympbyc:20150612195505j:plain

この画像をよく見ると、一部隠れているもののウインドウのタイトルが読めます。CRowViewCL。まずはこれをGoogleサーチしてみました。

CRowViewCL - Google Search

検索結果は一件。 なんと件の環境をブラウザ上に再現しているサイトが出てきます。

http://mebious.neocities.org/public_html/Infornography.html

f:id:ympbyc:20150612200026p:plain

mebious.neocities.org 謎しかないけどワイヤードの世界を体験出来ます。 誰か詳細知ってたら教えてください。 wired.entry.neocities

このページのおかげでわかったことは、CRowViewCLは実在のソフトウェアではないことと、件のエディタがIDEであるということ。確かに元画像にもIDEという文字は見て取れます。

Apple NewtonやCoplandへのリファレンスから、最初はMacNeXTSTEPかのソフトウェアかと推理したのですが、よく観察するとどうもそうではなさそうです。

  1. メニューバーがウインドウに内包されている。
  2. フォントがChicagoだ。

Copland ProjectのPinkのスクリーンショットでも、メニューバーは画面上部にあり、Chicagoフォントが使われているのが確認できるので、アップルのシステムという線は捨てて捜査を進めました。

ではなんなのか

このページによると、各エピソードの終わりに表示される"To Be Continued"のBeのカラーリングがBe Inc.の昔のロゴをリゼンブルしているらしい。BeOSも出自からしAppleと関係が深い。ビビビッと来ましたね。

f:id:ympbyc:20150613134904p:plain

おもむろに"BeOS IDE"と検索してみると……ビンゴ!

f:id:ympbyc:20150612203337j:plain

  • フォントが一致. どちらもCourier 10 BT Roman
  • ウインドウの枠線が一致。1pxの線と直角を多用するBeOSの可愛らしい特徴が出ています
  • メニューバーの色が一致
  • メニューバーの項目、File   Project   Windowが一致。ツールバー右端にはみ出ている Data が決定的証拠.
  • ツールバーの下の sources が一致

この画面は、 CodeWarrior 1.5 for BeOSスクリーンショットです。CodeWarriorなんて初めて聞いたけど、XCode以前に一大帝国を築いていたIDEらしいです。対応言語はC,C++,Pascal,Javaで、残念ながらCommon Lispは入っていないようです。

HandiNaviで動くLispの開発環境CRowViewCLのモデルは、Code Warrior for BeOSだということが判明しました。

また、HandiNAVIでBeOSのバイナリが走っていることから、Copland OS EnterpriseはBeOSの亜種なのではないかという仮説が立ちます。

Code Warrior for BeOSlainを結びつける記述はどこにも発見できなかったので、きっと新発見だと思います。

せっかくなので再現画像を作ってみました。Code Warrior for BeOSのウインドウに、Emacsでハイライトしたライフゲームソースコードをハメ込んでいます。

f:id:ympbyc:20150612215426p:plain

Reptoidsボタンがあるツールバーは依然謎のままです。昔の映像だと、他のボーダーはスムースなのにツールバーの上だけジャギってるので、ハメ込みじゃないかと思ってます。ちなみにReptoidはヒト型爬虫類のことです。あとは頼みます。

HandiNavi=Palm説 (追記 2018/09/30)

Reptoidsの出処を突き止めました。Reptoidという名前のゲームがCodeWorriorのPalm OSSDKにサンプルとして付属していたようで、Palm,Inc.のRoger Floreというハッカーが作ったもののようです。

出典: Palm Hacker's Salon CodeWarrior講座 第2回 サンプルを改造してみる

f:id:ympbyc:20180930002313g:plainf:id:ympbyc:20180930002319g:plain ツールバーに注目

HandiNaviのハードウェアはApple Newtonをモデルにしているというのが定説ですが、Palm説も浮上してきました。

というわけで幻の開発環境の正体の本命は、Palm上のBeOSで動くCommon Lisp対応のCodeWorriorということになります。

f:id:ympbyc:20181001151126p:plain


p.s. 

  • BeOSが気になってきた方はHaiku OSとかいじってみると楽しいと思います。
  • Code Warriorの体験談お寄せください。

Source code - SEL wiki

Clojure界隈楽しい & life on runtime

Clojure/West 2015のビデオ見始めたんですが、今年は豊作だったみたいですね。

多次元パラメータスペースを使ったジェネレティブアート。最高! Quilの上にMany Worldsってライブラリを作ったそうです。

www.youtube.com

前から気になってたcloxp。githubできてた。今日ちょっと触ってみて #tokyoclj で軽く紹介しました。JS版Smalltalk環境のLively Kernel上のClojureの開発環境という、超ニッチなところ攻めて来てます。ランタイムでlive object触って開発するのまじ楽しっすよ。今度のSmalltalk勉強会で日本のSmalltalker達に紹介する予定です。

www.youtube.com

ランタイムで開発といえば、ちょっと違うけどもう一つ。Figwheel。ランタイムの状態を壊すことなくトライアンドエラーサイクルを回せるってもの。こちらは普通のエディタ使えるのでマス受けしそう 。 www.youtube.com

まだいくつかしか観れてないですが、他にも面白いtalkいっぱいあります。乱数のやつとか。Clojure界隈不思議なことしてる人が多くて楽しいです。Something beyond ordinary programmingみたいなの好きな人は要チェック!

www.youtube.com

ランタイムでの開発って話でいうと実は僕も作ってるものがあって、近いうちに発表できるとこまで持って行きたいなと思ってます。Fluxアプリをブラウザ上で開発しちゃおうってもの。これはClojure関係なくてVanilla JS。まだPoCでWIP. よかったら一緒にやりましょう。

github.com

なんか久しぶりに開発意欲が湧いてきた。 #tokyoclj 行ってよかった。来週のClojureScript勉強会も行きます。