配列処理

PostScriptでのfold,map,filter等を作ってみる。

fold

forallをそのまま使うだけでfoldの動作が出来る。
以下は1から3までの和を求める例。

GS>0 [1 2 3] {add} forall ==
6

が、自分の好みにより引数の順番を変えたものをfoldとする。

GS>/fold {3 1 roll forall} def
GS>[1 2 3] {add} 0 fold ==
6

map

まずは組み込みの命令だけでやってみる。
以下は各要素を2倍する例。

GS>[ [1 2 3] {2 mul} forall ] ==
[2 4 6]

よって、mark([)を配列の前に挿入してからforallと]を実行すればよいことがわかる。

GS>/map {[ 3 1 roll forall ]} def
GS>[1 2 3] {2 mul} map ==
[2 4 6]

filter

まずは組み込みの命令だけでやってみる。
以下は3未満を取り出す例。

GS>[[1 2 3] {dup 3 lt not {pop} if} forall] ==
[1 2]

いい方法が思いつかなかったのでとりあえず引数の{3 lt}をローカル変数predに入れるバージョン

GS>/filter {1 dict begin /pred exch def [ exch {dup pred not {pop} if} forall ] end} def
GS>[1 2 3] {3 lt} filter ==
[1 2]

iota

まずは組み込みの命令だけでやってみる。
以下は1から3までの配列を作る例。

GS>[ 1 1 3 {} for ] ==
[1 2 3]

めんどくさいので、引数はfor命令の初期値、増分、上限の順をそのまま採用。

GS>/iota {[ 4 1 roll {} for ]} def
GS>1 1 3 iota ==
[1 2 3]

組合せ

出来た各命令を組み合わせて使ってみる。
1から3までの配列を作って、3未満を取り出して、各要素を2倍して、全てをたしあわせる例。

GS>1 1 3 iota  {3 lt} filter  {2 mul} map  {add} 0 fold  ==
6

うん、いい感じ(←自画自賛

おぼえがき

forallはarray(とは限らないけど)とprocの2つの引数をとる
forall実行開始時に2つの引数はpopされる
その後arrayの1つめの要素をpushしてprocを実行する
処理後1つめの要素がスタックに残るかどうかはprocの内容次第
次にarrayの2つめの…を最後の要素まで繰り返し。

n 1 roll はn番目に送り込む
n -1 roll はn番目を取ってくる

配列は、[0 1 2 3] のようにして作る。ただし、[ はただの mark で、] は mark からスタックの一番上まで要素に持つ配列を作るという命令なので、[ と ] の間で計算ができる。forall と組み合わせると楽しい。

http://d.hatena.ne.jp/yshl/20070910

確かに楽しかった。