假设我在堆栈上有两个程序p1
和p2
,我想要使用它们并在堆栈上留下一个结合其效果的新程序。我想要一个程序来做到这一点。如果我总是愿意做一些字典簿记,这很容易。但是我可以不引入任何名字吗? (请注意,我想要生成的过程,而不仅仅是在当前堆栈上执行组合效果。)
考虑例如
/compose {<< /f1 4 2 roll /f2 exch >>begin {f1 f2} end}bind def
当然,这不会起作用,因为在end
之后f1和f2将是未知的。但是这个破碎的代码应该说明我之后的事情。
答案 0 :(得分:1)
这完全可能,而且非常困难。您使用每个过程对象后跟可执行文件名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
所有标记为前缀为双斜杠//
的标记。注释<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
或者,实际上以正确的方式放置参数,它可能如下所示。使用forall
循环模拟向后for
会更加尴尬。
/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