沖縄在住の新進気鋭の超絶技巧プログラマであるりゅうくん主催の会に参加してきました。
ずっとRubyで変なことをやってるhanachinさん、TRICK 2018で5作品入選で鮮烈な存在感を発揮したぺん!(tompng)さん、元同僚でギークハウス沖縄オーナーのさぼさんを始めとする東京と沖縄の変なプログラマが参加してくださいました。
主催のりゅうくんによるまとめ
MatzLisp
話の枕として持ってきた記事はこれです。
なんかもともとは2013年6月にノリで書いたコードっぽくて、それをTRICK 2015に応募したけど玉砕しました。
僕のコードはインデントをくふうしただけの一発ねたなのですが、その年にはk-tsjさんのめっちゃ完成度が高いコードがMatz Lisp Awardとして受賞してたので玉砕は完全に納得です。
あとこのファイル名なのですが、脆弱性として利用可能な拡張子偽装ができるWindowsの「仕様」として著名なものです。
(let [])
って書いてるあたりにClojureとして誤認されたさが垣間見えてますね。まともにClojureを書いてる人は絶対誤認しないですけど… このスクリプトの正しいファイル名は choise.[RLO]jlc.rb
です。jlc
が反転してclj
に見えるんですね。UIぶっこわれてますけど。
一方でGitHub - Bug Bounty Program | HackerOneによれば、
とのことで、これは脆弱性ではないらしいです。ふーーーん。
あと、いまこの記事を書くまで忘れてたんですが、上記の本のRubyによるScheme処理系をLispっぽいインデントで書いてました。完全に記憶から消し飛んでたよ。
Objective Programming Paradigm
自分が実装したDSLっぽいものだと最初期の2012年頃に書いたやつだった気がします。元ねたは当時たしか高専生だったLisper(Schemer)の某氏がTwitterとGistに投げてた言語を適当に再実装してみたやつです。未だにそうなのですが他人が文章で説明してるけど理解できないことが多いので、自分なりに再実装してみる癖があります。
メッセージ送信演算子の選択ですが、Rubyで再定義できる演算子のうち **
だけが右結合 だったので選びました。 (目的は美しいDSL設計ではなくObjective Programming Paradigmの概念実証だったので)
演算子の結合順序に関して気になるひとはこんな感じのクラスを定義してIRBとかで a * b * c
とか a ** b ** c
とかやって遊んでみてください。へんてこDSLを実装してどうしても右結合性が欲しくなったら **
。おぼえておいてください。
class Foo def initialize(v) @v = v end def inspect "#<Foo, @v=#{@v.inspect}>" end def **(sbj) p [sbj, self] self end def *(sbj) p [sbj, self] self end end a, b, c = Foo.new(:a), Foo.new(:b), Foo.new(:c)
この元コードを書いた某氏は数年前にWeb上の一切合切の痕跡を断ってしまったのですが(そのあと一度だけ会ったことはある)、元気にしてるかなあ。奴とこの言語の話をしたことはないので、僕の解釈が合ってたのかはよくわからないです。
クラスローダーを使ったPHPメタプログラミング
PHPに詳しくないひとが多かったので前提から説明しました。
そしてPHPの全ファイルで機能する use
の代替をクラスローダーで実現するやつです。
要はそれぞれの名前空間にエイリアスを生やしまくることで実現します。実行時のパフォーマンスのペナルティは(たぶん)あまりないような気がします。ちゃんと計測してないけど。アルゴリズム改善の余地はあるかも。
PHPで無名再帰
PHPには use
と変数リファレンスを利用することで Closure
の再帰ができます。もちろんそれが常套手段なのですが、その制約を超えて再帰するテクニックを二つ紹介しました。
一つめにZコンビネータを利用する方法。これは不動点コンビネータの一つです。
ここで関数
f
の不動点とは、f(x) = x
を満たすようなx
のことをいう。
不動点コンビネータとしてYコンビネータで、アメリカのシードアクセラレーター(ベンチャーキャピタル)として著名なY Combinator LLCの社名として有名です。
WikipediaにはJavaScriptでの不動点コンビネータの例があります。これはYコンビネータを正格評価の言語でも実行可能なように変形したものです。さらにそれをPHPで利用可能なようにしたものをライブラリにしてあります。
変なコード紹介の場としてはこっちを見せた方が盛り上がったかもしれませんね。
で、第三の無名再帰の方法として最近発見したのが無名クラスを利用する方法です。
はじめに、PHPのクラスに__invoke()
マジックメソッドを実装すると、そのクラスのインスタンスオブジェクトを関数のように呼び出しができるようになります。そしてPHP7には無名クラスが導入されました。しかしながら無名関数には名前がないのに対し、無名クラスには名前があるのです。何を言ってるのか? __FUNCTION__
や __METHOD__
、 __CLASS__
などのマジカル定数を出力するとわかります。
<?php call_user_func(function(){ var_dump(__FUNCTION__); }); // string(9) "{closure}" call_user_func(new class{ function __invoke(){ var_dump(__METHOD__); } }); // string(87) "class@anonymous\000/Users/megurine/Dropbox/junk/2019/06/qr_omSMR3.php0x10aede09e::__invoke"
これの性質を利用して無名クラスで call_user_func(__METHOD__)
と書くと自分自身を呼ぶことができます。
無名関数の __FUNCTION__
が {closure}
としか出力されないのに対して、無名クラスの __METHOD__
はファイル具体的なクラス名が含まれてます。……クラス名?そう、 class@
とか \0
とか /
とか常識的なクラス名には含まれない文字がいっぱい入ってますがクラス名です。種明かしをすると無名クラスは無名ではなく、アクセスしにくい名前が付けられた、ただのクラスなのです。
正確には無名再帰ではないのですが実際無名関数と同じことが短く書けるので、まあまあ嬉しいですね。
ELVM
ELVMはShinichiro Hamaji(shinh)さんによる、多数の言語にコンパイルできるコンパイラインフラストラクチャです。
具体的な説明はshinhさんによるスライドと記事をお読みいただくのが良いです。
任意のプログラムをELVM IRで表現できれば、いわゆる難解プログラミング言語を含むバックエンドによって任意の言語に変換することができます。極めつけは8ccが移植されてるので、「Brainfuckで動くCコンパイラ」のような意味不明なものが実現されてます。実用性はともかく、チューリング等価って本当に等価なんだなあと実感することができます。
前置きはさておき、2016年頃にPHPのバックエンドの実装を送ったときの昔話をしました。
一から書くのは難しそうだな…! と思ったのでJavaScript実装をPHPっぽく書き直すところから作業を始めました。
HTML+CSSとチューリング完全
ぺん!さんのCSSだけで動くライフゲームが衝撃的すぎたので、(2012年に書いた記事なので自分の中では黒歴史に近いのですが)むかしの自分の記事をほじくり返しました。
こんな関係です。
あと、フォントの合字で計算できるのでは? って話が出てたので、二年ほど前ににせねこさんが作ってたOpenTypeで万年カレンダー(2019/06
のように並ぶとフォントでカレンダーが表示される)を紹介しました。
PHP voidクイズ
せっかくなので一年ちょっと前にTwitterに上げたねたの話をしました。
PHPクイズ: この中で、Syntax Errorが検出される一番上の行はどれ?? pic.twitter.com/zwHXYaYuti
— たっどさんおぼえた。 (@tadsan) February 15, 2018
詳しいことはQiitaに書きました。そちらには上記のクイズをさらに意地悪にしたバージョンがあります。
このクイズは会場ではhanachinさん一人が正解されました。PHPの予約語って難しいですね…!
まとめ
まとめも何もないのですが、ぺん!さんやhanachinさんの超絶技巧を間近で目の当たりにしたのは楽しかったです。あとりゅうくんのライブ記号プログラミングやばい。
最近沖縄界隈がめちゃくちゃ活発なので、興味を持った人はギークハウス沖縄もよろしく!
あとギークハウス沖縄の近くのチャーリー多幸寿がめちゃくちゃおいしかったです。