Hello, polyglot!
きっかけ: るびま これを読んでpolyglotするかーって思った.
今回のコンセプトは
- 初めてなのでやさしくHello, world!
- 好きな言語を盛り込む
- 140文字以下
ソースコード
できあがったのがこれ.
;(#)={-"^<"v 'v+55p44p41< (define puts print) ;')#>:#,_@-}0;puts=putStrLn;main= (puts"Hello, world!")
言語紹介
Scheme
S式と呼ばれる単純な文法で記述する言語.括弧で括ると何かが起きる.行コメント ;
ネスト可能なブロックコメント #| ... |#
に加えて式を一つコメントアウトする式コメント #; expr
がある.
"
は文字列リテラルに使われるが, '
はquoteといって続く式は評価されずリテラルになる.'foo
はシンボルへ,'(foo bar baz)
はリストへと読まれる.
いろんな文字が識別子に使えるのも特徴.+ - < >
など.
Ruby
独特の複雑な文法で記述する,改行が意味を持つタイプの言語.あちこちで括弧を省略できる.#
で行コメントはできるが,複数行コメントはちょっと使い辛い.
"
と '
はどちらも文字列リテラルに使われる.似たようなものに /
で開始する正規表現リテラルがある他,%!...!
や %q!...!
(!
は任意の非英数字)等の多様なリテラルを持つ.
Haskell
インデントが意味を持つタイプの言語.トップレベルには(多分)宣言と定義しか書けないので,今回使用した言語の中では最も文法上の制約が強い.行コメントは --
ネスト可能なブロックコメントは {- ... -}
でできる.
静的型付き言語なので,型の整合性も取らなければならない.
Befunge
1文字1命令で,実行の向きを変えながら二次元格子状のコードを実行していく難解言語.コメントのための機能は無いが,意味のある命令以外は無視される.
スタック型.小さい整数を扱う事ができる.実行中のコードを読み書きできる.
Scheme着色版
;(#)={-"^<"v 'v+55p44p41< (define puts print) ;')#>:#,_@-}0;puts=putStrLn;main= (puts"Hello, world!")
Ruby着色版
;(#)={-"^<"v 'v+55p44p41< (define puts print) ;')#>:#,_@-}0;puts=putStrLn;main= (puts"Hello, world!")
Haskell着色版
;(#)={-"^<"v 'v+55p44p41< (define puts print) ;')#>:#,_@-}0;puts=putStrLn;main= (puts"Hello, world!")
Befunge着色版
;(#)={-"^<"v
'v+55p44p41<
(define puts print)
;')#>:#,_@-}0;puts=putStrLn;main=
(puts"Hello, world!")
解説
1行目
Schemeをコメントアウト.Haskellでは演算子 (#)
の定義の途中から4行目の途中までコメントアウト.これによってRubyも開き括弧だけしてコメントアウト.Befungeでは前半は無意味なコードで,後半にコード書き換え用の文字をスタックに積んで下へ.
2行目
Schemeでは quote
により離脱.同時にRubyは4行目の頭まで文字列リテラルにより離脱.Befungeではここを右から実行してきて,5行目の文字列を読むための命令を5行目に書き込む.
4行目
Schemeはコメントアウト.Rubyはここで文字列リテラルから復帰して括弧を閉じ,あとはコメント.Befungeではここ >:#,_
が出力部になっていて,スタックに積まれた文字列を出力し終了するようになっている.後半はHaskellがコメントから復帰し,(#)
の定義を終えて puts
を定義,main=
を置いておく.
没コード集
その1
;{->{55+48+v (define putStr display) '|#:\g5+9: <-1_' }=>0};alias putStr puts #>:#,_@|;-}main= (putStr"Hello, world!\n")
121打.(define putStr display)
がRubyでも文法上は妥当なことを利用し,ラムダ式 ->{ ... }
をコメント的に利用したコード.Rubyでは括弧を補うと (define(putStr(display())))
と解釈される.実行されなければどうということはない.1行目の 55+48+v
はBefungeのためのコードだが,2行目と同様にRubyでも文法OKなので書ける.
Schemeで |...|
が一つのシンボルになることを利用した式コメントが気持ちいい.
出力関数の名前はHaskellの putStr
に合わせている.
Befungeは文字列リテラル部分をg命令で読み取るようになっていて,長さが埋め込みなのがちょっと残念.
その2
eval'=eval'&&'p' {-0=>(alias putStr puts)} "> 55+48+v |#:\g6++49:<-1_ >:#,_@"#t(define putStr display)' ;#-}where _&&x=x main=(putStr"Hello, world!\n")
153打.eval
がSchemeでもRubyでも定義されていて,Befungeが下に脱出できるのを利用したコード.Befungeの変なコードなんか全部文字列にしちゃえば簡単じゃないかというコンセプト.しかし長くなりすぎた.似たような方法に format
を使う手がある.
その3
;{->{55+48+v (define puts print) '|#:\g4+7:<-1_' }=>':#,_@|;'}#-}puts=putStrLn;main= (puts"Hello, world!")
108打.その1の改良版.出力関数の名前はRubyの puts
に合わせている.
その4
;{->{"2^<"^ (define puts print) '|0/5p42p4<' }=>':#,_@|1;'}#-}puts=putStrLn;main= (puts"Hello, world!")
104打.その3の改良版.Befungeのアプローチを変えて,文字列の長さが埋め込みでなくなった.