這是完全可能的,而不是非常困難。您使用每個過程對象和可執行文件名稱exec
創建一個新數組。然後使該數組可執行。
/combine { % {a} {b} . {{a} exec {b} exec}
/exec cvx exch % {a} exec {b}
/exec cvx % {a} exec {b} exec
4 array astore % [{a} exec {b} exec]
cvx % {{a} exec {b} exec}
} def
對於風格更接近原始的,使用參數名,我會寫這樣的:
% fun1 fun2 compose proc
/compose { 2 dict begin % f1 f2
{f2 f1}{exch def} forall %
({ //f1 exec //f2 exec }) % ({ //f1 exec //f2 exec })
cvx exec % { <f1> exec <f2> exec }
end } def
的//immediate-name
語法是非常強大的。這裏我使用一個字符串中的代碼模板。當字符串被執行時cvx exec
它調用掃描器的內容,然後它自動load
s所有標記以雙斜槓//
作爲前綴。註釋<f1>
指示了命名變量的內容。就像程序流中的{executable array}
未執行,但生成堆棧中的proc,exec
如果包含一個字符串,也會生成堆棧中的proc。
對於命名參數樣式,我使用了postscript的一些特殊規則:可執行數組不會執行,因此變量名稱數組可以寫成可執行數組,然後用作數據而不會有任何額外的麻煩。但通過使用可執行語法,可以在不使用/
的情況下編寫內容 - 名稱。所以,而不是[ /f2 /f1 ]
我們可以寫出更短的{ f2 f1 }
。
參數部分也可以被分解到它自己的函數中。
/argsbegin { % a r g s _ {n a m e s} . -
dup length dict begin
{exch def} forall % currentdict:<</n _ /a s /m g /e r /s a>>
} def
/compose { {f2 f1} argsbegin
({//f1 exec //f2 exec}) token pop exch pop %another way to invoke the scanner
end } def
或者,爲了實際上將參數放在正確的位置,它可能如下所示。用for
循環來模擬倒退forall
只是稍微有些尷尬。
/argsbegin { % a r g s _ {n a m e s} . -
dup length dup dict begin % a r g s _ {} n
1 sub -1 0 { % a r g s _ {} i
3 2 roll % a r g s {} i _
3 copy % a r g s {} i _ {} i _
pop % a r g s {} i _ {} i
get % a r g s {} i _ /s
exch def % a r g s {} i
pop % a r g s {}
} for % {}
pop
} def
/compose { {f1 f2} argsbegin
({//f1 exec //f2 exec}) cvx exec
end } def
不錯。我試圖找出一種使用'exec'的方法,但是我沒有意識到我可以在堆棧上推送字面名稱,然後使其可執行。謝謝。 – Alan
你非常歡迎。我喜歡真正進入編程方面的後記問題。在我的[文檔格式引擎](https://github.com/luser-dr00g/ibis.ps/blob/0c0aa7d5bd683d21d9814b2b697a85028bcddc81/ibis.ps#L750)中有一個更復雜的例子,從750到850行定義了一個函數稱爲'addstyle',它執行* morphisms *(變化狀態/恢復狀態函數對)的組合。 –
稍早的同一個程序的草稿是[複習](http://codereview.stackexchange.com/questions/117320/document-formatting-markup-engine-in-postscript),但在GitHub上閱讀更容易行號和語法突出顯示。 –