-
Notifications
You must be signed in to change notification settings - Fork 1
0 木構造の演算(18種)
この項ではUltraPietの具体的な仕様を見ていくことにしましょう. まずは記法の定義から見ていきましょう. DirectionPointerをDPと略します. CodelChooserをCCと略します.
空のスタックに順番に, 1 をPush, 2 をPush, 3 をPush, 4 をPush した時, スタックの変化を [] => [1] => [1,2] => [1,2,3] => [1,2,3,4] と表記します. つまり,一番右にあるものが一番最近Pushしたものとなります.
また, [1,2,3,4] にAdd命令を行うことを, Add [1,2,3,4] => [1,2,7] と表記できます. この場合,1,2 は直接演算に関係ないので, Add [...,3,4] => [...,7] のように記すことができます. さらに演算に関係ない項目 ... を省略し,以降の文章では Add [3,4] => [7] のように記します. 例えば,Sub[7,2] =>[5] は,7 - 2 = 5 をしたことを意味しますね.
また,UltraPietでは前述のとおりintと木構造のみで構成されています. 木構造から,文字処理のために糖衣構文を定義しておきます. まず,65 ="A"; 66 ="B";67 ="C";とUnicodeで対応しています. 文字処理のために [65,66,67] と積んだ場合, その数字が何を指しているかで表現したほうが見やすいので, [65,66,67] = [A,B,C] と表記しましょう. さらにもっと省略して,[A,B,C] = "ABC" という糖衣構文も定義します. UltraPiet ではintと木構造しか使わないということは 大事なことなので忘れないでください.
UltraPietでは新たに2つの命令を導入します. 既存のPietと競合しないように導入しなければなりません. そこで,普通しない命令である 0除算命令,0剰余命令に 新たな命令としての意味を持たせるという形で導入します.
Div [n,0] => []
n.png という名前のPietを読み込んで実行します.
現在の標準入力,標準出力,スタックのまま,
そしてDP は 0 ,CC は 1 で初期化されて
そのPietを一番左上の位置から実行します.
終了後,退避されていたDP,CCは元に戻ります.
この命令によりファイルをモジュール化でき,
ファイルの分割が可能になります.
Mod [...,x1,x2,...,xn,n,0] => [...,[x1,x2,...,xn] ]
深さnまでの要素を積んだ新たな木構造をPushします
この関数により,UltraPietのスタックに,
新たに木構造を積むことが出来るようになります
例: Mod [...,C,H,Y,3,0] => [...,[C,H,Y] ]
今回の拡張によってintだけでなく木構造も積めるようになりました. 木構造同士の演算を新たに定義しましょう. 木構造と木構造,数字と数字との演算なら問題はないのですが, 木構造と数字が混じっていた場合についてはちょっと考えないといけません. 結論としては,その数字を一つのみを要素とする新たな木構造を作成して, それを利用して木構造と木構造の演算として扱います.
例えば,加算の関数 Add は,
Add [...,72,28] => [...,100] と,数字同士なら演算されますが,
木構造同士に Add を作用させると結合の意味になります.
例:) Add [...,[A,B,C],[X,Y] ] => [...,[A,B,C,X,Y] ]
そして,数字と木構造の演算の場合は,
その数字を一つのみを積んだ新たな木構造を作成して,
それを利用して木構造と木構造の演算として扱うので,
Add [...,C,[H,Y] ] => Add [...,[C],[H,Y] ] => [...,[C,H,Y] ] と計算されます.
それでは早速命令を見ていきましょう!
Push , In(char) , In (number) はスタックとしては定義されません.
スタックの先頭から一つとり,それに演算を適用します.
型 :: [...] => [...]
木に木が積まれて,更にそれに木が...という状態に
陥いったときにそれを全て平坦化してくれます.
例を見てみますよ.
- Switch [...,[A,[B,C,[D],E],F,G] ] => [...,[A,B,C,D,E,F,G] ]
- Switch [...,[A,B,C] ] => [...,[A,B,C] ]
- Switch [...,[A] ] => [...,[A] ]
- Switch [...,[] ] => [...,[] ]
型 :: [...,T] => [...], T
木構造の先頭要素を一つとりだしてPushします.例をあげましょう.
- Point [...,[A,B,C] ] => [...,[A,B],C]
- Point [...,[A,B,C,[X,Y] ]] => [...,[A,B,C],[X,Y] ]
- Point [ Xn,Yn],...,[X1,Y1] => [ [[Xn,Yn],...,[X2,Y2] ],[X1,Y1] ]
- Point [...,[A] ] => [...,[],A]
- Point [ [] ] => []
型 :: [...] => [...],[...] 数字版のDupと同じです.例を見せます.
- Dup [...,[ [1,3,4],4,32] ] => [...,[ [1,3,4],4,32],[ [1,3,4],4,32] ]
型 :: [...] => Num
数字版のNotと意味的には一緒です.
NotとSwitchを組み合わせることで(必ずこの演算の後は生の数字なので)安全に条件分岐が使用出来ますね.
- Not ["Hello"] => [0]
- Not [ [A] ] => [0]
- Not [ [] ] => [1]
型 :: [...] => []
数字版のPopと一緒です.例を一応載せときます.
- Pop [ [A,B,C] ] => []
型 :: [...] => []
Switchで平坦化して文字列と見なせるようにしてから出力します.
- Out(Char) [ [C,H,Y] ] => [] : "CHY"と出力する
- Out(Char) [ [千,早] ] => [] : "千早"と出力する
- Out(Char) [ [C,[H,I,[H,A],Y],A] ] => [] : "CHIHAYA"と出力する
- Out(Char) [ [C] ] => [] : "C" と出力する.
- Out(Char) [ [] ] => [] : 何も出力しない.
型 :: [Tn,...,T1] => Tn,...,T1,Num
Out(Num) という名前ですが出力はしませんので注意して下さい.
Mod0命令の逆演算となります.
- Out(Num) [...,[A,B,C] ] => [...,A,B,C,3]
- Out(Num) [...,[A,[B,C],D] ] => [...,A,[B,C],D,3]
- Out(Num) [...,[A] ] => [...,A,1]
- Out(Num) [...,[] ] => [...,0]
Div 0 の 被除数が 木構造の場合,それをSwitchで平坦化して 文字列にし,その文字列のパスにあるPietモジュールを実行します.
Mod [...,x1,x2,...,xn,n,0] => [...,[x1,x2,...,xn] ]
深さnまでの要素を積んだ新たな木構造をPushします.
x1,...,xn が木構造の型であっても大丈夫です.
n が木構造であった場合は n = ∞ として(つまり深さ無限で)演算します.
- Mod [...,C,H,Y,3,0] => [...,[C,H,Y] ]
- Mod [...,[C,H,I],[H,A,Y,A],2,0] => [...,[ [C,H,I],[H,A,Y,A] ] ]
- Mod [...,C,H,Y,[],0] => [ [...,C,H,Y] ]
スタックの先頭から2つとり,それらに演算を適用します.
型 :: [...],[...] => [...]
単純に結合します.例を示します.
[A,B,C] ="ABC" という糖衣構文を思い出してくださいね.
- Add [...,[C,H,I],[h,a,y,a] ] => [...,[C,H,I,h,a,y,a] ]
- Add [...,"CHIhaya","isGOD") => [...,"CHIhayaisGOD"]
- Add [...,1,[10,100,1000] ] => [...,[1,10,100,1000] ]
- Add [...,[1,10,100],1000] => [...,[1,10,100,1000] ]
- Add [...,[A,B,C],[] ] => [...,[A,B,C] ]
- Add [...,[],[] ] => [...,[] ]
型 :: [...],[...] => [...]
Switch で平坦化し,文字列として見なせるようにしてからSplitします.
[A,B,C] ="ABC" という糖衣構文を思い出してくださいね.
- Sub [...,"Pietはx楽しい","x"]=> [...,["Pietは","楽しい"] ]
- Sub ["12/12 21:41"," |/|:"] => [ ["12","12","21","41"] ]
- Sub [...,"helloHWWH!",H] => [...,["hello",[W,W],[!] ]]
- Sub [...,[h,[e,H],[l,l,[ [o] ]] ],[H] => [...,["he","llo"] ]
- Sub [...,H,"\s"] => [...,[H] ]
- Sub [...,H,"H"] => [...,[] ]
型 :: [...],[...] => [...]
便利な未来を作る直積集合ですよ.
- Mul [ [A,B,C],[X,Y] ] => [ [ [A,X],[A,Y],[B,X],[B,Y],[C,X],[C,Y] ] ]
- Mul [...,H,[J,I] ] => [..., [ [H,J],[H,I] ] ]
- Mul [...,[A],H] => [...,[A,H] ]
- Mul [...,[],A]=> [...,[] ]
- Mul [ [A,B,C],[ [X,Y] ]] => [ [A,[X,Y] ],[B,[X,Y] ],[C,[X,Y] ]]
- これにより,例えば 0 < n,m ≦ 20 の n * m の取りうる値を列挙できます
- 1~20までと20と0を順に積む => [1,...,20,20,0]
- Mod0 を実行して木構造化 => [ [1,...,20] ]
- Dupでコピーを作成 => [ [1,...,20],[1,...20] ]
- Mul で直積を取る => [ 1,1],...,[20,20]
- Point で先頭の要素を取得 => [ [[1,1],...,[20,19] ],[20,20] ]
- Out(N)で分解する => [ [[1,1],...,[20,19] ],20,20,2]
- 2 を Pop => [ [[1,1],...,[20,19] ],20,20]
- Mulで掛け算する => [ [[1,1],...,[20,19] ],400]
- Roll 2 1 で入れ替える => [400,[ [1,1],...,[20,19] ]]
- 5~9 を繰り返す.
- [400,...,1] が出来上がる.
型 :: [...],[...] => [...]
Switch で平坦化し,文字列として見なせるようにしてからMatchします.
[A,B,C] ="ABC" という糖衣構文を思い出してくださいね.
- Div ["aa9bb1cc",".[1-9]."] => [ ["a9b","b1c","aa9bb1cc"] ]
- Div ["aa",".[1-9]."] => [ [] ]
- Div ["aHxH",H]=> [ ["H","H","aHxH"] ]
- Div [H,"h|H"] => [ ["H","H"] ]
- Div [ [],"A|B"] => [ [] ]
- Div ["ABC",[] ] => [ [] ]
型 :: [...],[...] => [...]
それぞれの要素を結合します。Mulと上手く組み合わせてご使用下さい。
- Mod ["01234","abc"] => [ ["2a","3b","4c"] ]
- Mod [ [a,b,c,d,e],[x,y] ] => [ d,x],[e,y]
- Mod [ a,b,c],[d,e] ],[x,y] ] => [ [[ [a,b,c],x],[ [d,e],y]
- Mod [H,"abc"]=> [ [H,c] ]
- Mod ["abc",H]=> [ [c,H] ]
- Mod ["abc",[] ]=> [ [] ]
- Mod [ [],[] ]=> [ [] ]
型 :: [...],[...] => Num
ファイルを開いて標準入出力へリダイレクトします.
成功したら 1 ,失敗したら 0 が積まれます.
第一引数は開くファイル名です.
第二引数は開くモードを指定します.
モード
- [R] or [0] : 読み込み(Read)モードで開く.
- [W] or [1] : 書き込み(Write)モードで開く.
- [A] or [2] : 追加書き込み(Append)モードで開く
- [r] or [3] : Readで開いたファイルを閉じる.
- [w] or [A] or [4] : Writeで開いたファイルを閉じる.
- その他 : 現在開いているファイルをRead,Writeともに閉じる.
新たにファイルを開いた場合,現在開いているファイルは閉じられます. 例を示します.
- Greater ["f1.txt",R] => [1] : f1.txtを開き標準入力をリダイレクトする
- Greater ["f2.txt",1] => [1] : f2.txtを開き標準出力をリダイレクトする
- Greater ["f.t",R] => [0] : f.tが開けなかった.
- Greater ["f3.txt",A] => [1] : 2.で開いていたf2.txtを閉じて新たにf3.txtを 追加書き込みモードで開き,標準出力をリダイレクトする.
- Greater [ [],[r] ] => [0] : 1.で開いていたf1.txtを閉じる.
型 :: [...],[...],[...],[...] => Num or [...] or Empty
Pietが何でも出来るようになる魔法の関数です.
この関数により,ゲームやアプリを作ることが出来るようになります.
実用的なマルチメディアな操作をPietで体感しよう!
引数
第一引数 : DLLへのファイル名を含むパス
第二引数 : DLL内の関数名
第三引数 : DLLに渡される型の宣言
第四引数 : DLLを呼び出すための引数リスト
例
- Roll ["user32.dll","MessageBoxA", "vssui",
[ [],"Hello World.","Caption",0] ]
C製Dllであるuser32.dllの,MessageBoxA関数を呼び出します. "vssui"というのは的確にDLLを扱う為の型情報の宣言です. 引数の型は前から順に void*(HANDLE),char*(LPSTR), char*(LPSTR),unsigned int (UINT) で, 返り値はint型にするという宣言で, 前から順にvoid*,char*,char*,unsigned int,intなので 頭文字をとって "vssui"です.
以上がすべての命令です! おつかれさま!