*多変数による繰り返し [#g026111d] いきなりですが次のコードを見てみましょう: a(X):XXXXrXXXXa(sX) a(r) 【画像】 #ref(use_Y_1.png,nolink) 16byteで2重の正方形を回りながら描きますね. ~ これを2倍関数により解消しても, 実は短縮にはなりません. f(X):XX a(X):f(f(XX)r)la(sX) a(r) これだと17byteでかえってbyte数が増えてしまっています. もう少し工夫した2倍関数の利用により, 同byte数の16byteで動きを再現することは可能です. ~ f(X):XrX a(X):f(f(f(X))r)a(sX) a() ---- よりよい方法を考えましょう. ~ 再帰の一部ではなく, 次のような状況ならどうするでしょうか? ssssrssss これならわざわざ2倍関数を定義する人は少ないと思います. ~ このときは, 2回出てくる「ssss」または4回出てくる「ss」を文字で置いて~ y:ssss yry のようにすれば短縮になりますね. 2倍関数の利用よりも短くなります. ---- 実は同じようなことを再帰の一部でも使うことができます. ~ 具体的には次のようなコードで1byteの短縮に成功しています. ~ (実は最初のコードと少し向きが違うものを描くのですが...見逃してください. ) a(X,Y):YrYa(sX,XXXX) a(r,) #ref(use_Y_2.png,nolink) まさに, ''Y=XXXX''として, XXXXを他の文字で置いているのが分かりますよね. ~ 他にもXYXやXllXなどを他の文字で置くことにより短縮につながることがあります. もちろんn倍関数などを使うのが有利な場合もあるので, ~ (いつも書いているけど)色んな方法を念頭に置くようにしてください. ---- この方法にはいくつか注意点があります. ~ これはこの方法を使うときのリスクであるとともに, 裏を返せば~ 「この方法だからこそ書けるコード」に繋がる可能性もあります. まずは, ''「何段階目か」がずれる''ということです. ~ 先ほどのコードでは,再帰の「YrY」の部分はとして実行されるものは次のようになります: > 1段階目:r > 2段階目:[rrrr]r[rrrr] > 3段階目:[srsrsrsr]r[srsrsrsr] > 4段階目:[ssrssrssrssr]r[ssrssrssrssr] 2段階目のYに1段階目のXが代入されるため, 1段階目の実行では1段階目のXは反映されていないのです. ~ これが先ほど述べた > 実は最初のコードと少し向きが違うものを描く ことの理由ですね. つまり1段階目のYは, ある意味で使われていないのです. ~ 実はここを有効利用することもできます([[特殊な初項]]の講でも説明する予定です). 例えば a(X,Y):YrYa(sX,XXXX) a(r,sss) などと実行してみてください. #ref(use_Y_3.png,nolink) > 1段階目:[sss]r[sss] > 2段階目:[rrrr]r[rrrr] > 3段階目:[srsrsrsr]r[srsrsrsr] > 4段階目:[ssrssrssrssr]r[ssrssrssrssr] と実行されていくのが分かると思います. 初期位置を調整しながら再帰を実行し始めるような場合に, ~ 「YrY」という関数に好きなものを代入する形で使うことができます. ~ 過去にも少ないですがここを利用した短縮がありました. ---- 次の注意点を述べましょう. 例えば a(X):XXrXXrXXrXa(sX) a() というコードを見てみましょう. 「XXr」が多量に含まれるためにそこを文字で置いて a(X,Y):YYYXa(sX,XXr) a(,) としたくなる場面ですね. 実はこれではズレてしまいます. > n段階目の「Y」は, n-1段階目のXを用いた「XXr」である ためです. このように中途半端に他変数Yに預けると, XそのものとYで成長速度に差が出るのです. ~ 「わざと差をつける」ことで巧妙な短縮が出来る場面もあるのでテクニックとして~ 覚えておくとよいですが, 慣れないうちは間違えやすいので気をつけてください. ~ なおこのことを(3倍関数などを使わず)解消するに, Xも成長速度を遅らせる方法もあります. a(X,Y,Z):YYYZa(sX,XXr,X) a(,,) なお,実は上のコードは a(X,Y):YYYXa(sX,XrX) a(,) を実行したものと同じになります. この理由も考えてみると面白いかもしれません.