読者です 読者をやめる 読者になる 読者になる

Numbering #anagol

Numbering
最初に投稿した108bytesのコード

(defun f(n a)(dotimes(i 3)(or(format(> n 0)"~{   ~*~}~{~A~^.~}
"a #1=`(,@a,(1+ i)))(f(1- n)#1#))))(f(read)/)

(F)とか入ってそうなrepl変数 / が、コマンドライン実行時だとnilのままっていうのは新発見だった。
しかしうまいこと書けたと思ったけど1byte負けか… と思ってたら締切1日前にkozimaさんが強烈なネタをポスト

FizzBuzz 84bytes

(dotimes'101(format(> .'0)"~[Fizz~[Buzz~]~:;~[Buzz~:;~A~]~]
"(rem .'3)(rem .'5).'t))

束縛したquoteを利用する…だと…!?
(let'(a 0) ...)だとか(do'(a 1(f a)) ...)みたいな、quoteが無駄に束縛されるけど1byte縮むってネタは過去問見て覚えてたけど

(> .'0) => (> . (quote 0)) => (> quote 0)

こんな形で利用できるなんて事には思い至らなかったので衝撃的だった。
Numberingのコードでは2箇所で使えるねって事でquasiquoteも動員して

(defun f'a(dotimes`3(or(format(> .'0)"~{   ~*~}~{~A~^.~}
"a #1=`(,@a,(+ .`1)))(f(- .'1)#1#))))(f(read)/)

これで104bytes。kozimaさんも書いてたけど大分見た目がおかしくなってきた。

その後よくよく調べたらCLにはSchemeのquasiquoteのような特殊オペレータなんてないという事が分かって、あれどうなってんだ?って事になったのだけど、どうやらbackquoteの扱いは実装依存って事だった。
調べた範囲では、clispだとsystem::backquote, eclだとsi:quasiquoteがあって使い分けが可能だけど、sbcl, ccl, xyzzyでは適宜listやlist*の式に展開されるらしく、unquoteが全くない場合は

CL-USER> '(lambda 'a (lambda `b (+ a .'(+ .`b))))

(LAMBDA (QUOTE A) (LAMBDA (QUOTE B) (+ A QUOTE (+ QUOTE B))))

こんな感じになって使い分ける事ができない。


戻って、Arcでも同じ事できるかな?っという事で実験

arc> (with '0 (list .'1))
(0 1)

OK。しかし

arc> (with '0 nil)
Error: "reference to undefined identifier: nil"

nilSchemeレベルでは'nilで表現されてるため、quoteに値が束縛されとエラーになるらしい。おかげであなごるのコードが通らない。
じゃあquasiquoteなら

arc> (with `0 nil)
nil

OK。というわけで1位だったmurky-satyrさんの76byteのコードをこれで縮めると

((rfn f `n(or(> 0 --.n)(on i"123"(f(+"   "(prn:+ . `i)".")n))))""(read))

quasiquoteの前にスペースを入れるのは、Arcの字句解析がちょっと残念で

arc> 'a`b
|a`b|
arc> '(a .`b)
(a |.`b|)

となってしまうから。
このスペースなんとかならないかなーと、物は試しでunquoteを突っ込んでみた。

arc> ',a
(unquote a)

あれエラーにならないのか。調べると、Arcに限らずSchemeならOKらしい。しかしgolf的にはありがたい。
というわけで最終形は70bytes

((rfn f,n(or(> 0 --.n)(on i"123"(f(+"   "(prn:+ .,i)".")n))))""(read))

Arcの場合dotimesみたいな形は少ないから使える機会は少ないかもしれないけど、golfする人は覚えておこう。