記号のみを使った Julia プログラミングをしたかった
punctuations のみを使ってプログラミングすることを記号プログラミングと呼ぶ人がいるらしいです。*1
これを真似て Julia で記号のみのプログラミングをやってみようと思いました。上のリンク先の内容(特にPerlの記事)をなぞっただけなので新規性はないです。
記号のみでプログラミングをするための方策は次の2ステップに分解できます。
- 任意のAscii文字列を記号のみで表現する
- 作った文字列を eval する
この記事では 1. についてはやりましたが 2. は妥協しました。eval を記号で済ます方法は Julia にはないように思われたからです。
さて、まずは 1.を実現するために、任意の文字 [a-zA-Z]
が2つの文字記号の論理演算から作れるということを利用します。
julia> bin('`') "1100000" julia> bin('!') "100001" julia> bin('A') "1000001" julia> '`' $ '!' 'A'
この組み合わせは手作業で探してもいいですが、面倒なのでプログラムで全探索して辞書を作りました。
punctuations = "!\"#\$%&'()*+,-./:;<=>?@[\\]^_`{|}~" println("{") for i in ['A':'Z', 'a':'z'] lists = (Char, Char)[] for p in punctuations x = i $ p if (p, x) in lists continue end if x in punctuations push!(lists, (x, p)) end end println(" '$i' => $lists,") end println("}")
この辞書を元に好きな文字列を作ります。Julia では Char と String の扱いが異なり、+
記号を使ってカジュアルに Char を結合したりすることはできません。なので文字列挿入記法を使います。
julia> "$('`'$'(')$('['$'>')$('@'$',')$('@'$',')$('@'$'/'),$('^'$')')$('@'$'/')$('^'$',')$('@'$',')$('_'$';')!" Hello,world!
以上で任意の文字列を作ることに成功しましたが、ではこれを実行するにはどうしたらいいでしょう。Julia で文字列をプログラムとして評価するには parse
してから eval
する必要がありますが、これを記号だけで行う方法は見つけられませんでした。なので次のように単にアンダースコアで置き換えて妥協しました。これはひどい。
_ = parse __ = eval
こうすれば他の関数は記号のみで参照を得ることができます。例えば次のようにすれば記号のみで println
を使えるようになります。
julia> "$('^'$'.')$('^'$',')$('@'$')')$('@'$'.')$('\\'$'(')$('@'$',')$('@'$'.')" "println" julia> ___ = __(_("$('^'$'.')$('^'$',')$('@'$')')$('@'$'.')$('\\'$'(')$('@'$',')$('@'$'.')")) println (generic function with 2 methods)
これにより、(ほぼ)記号のみの Hello world プログラムを得ることができました。わーパチパチパチパチ!
_ = parse __ = eval ___ = __(_("$('^'$'.')$('^'$',')$('@'$')')$('@'$'.')$('\\'$'(')$('@'$',')$('@'$'.')")) ___("$('`'$'(')$('@'$'%')$('@'$',')$('@'$',')$('@'$'/'), $('\\'$'+')$('@'$'/')$('^'$',')$('@'$',')$('^'$':')!"))) # => Hello, world!
やってみたかっただけなので妥協部分をどうにかしようというモチベーションはありません。
*1:記号プログラミングという言葉を記号のみを使うプログラミングという意味で使うことは少し憚られます。Symbolic programming と混同する恐れがあるからです。なのでタイトルは記号のみプログラミングとしました。