|
% Examples for https://softwareengineering.stackexchange.com/questions/318297/almost-point-free-style |
|
|
|
% (parens) are PostScript syntax for strings. |
|
|
|
% String concatenation, stolen from https://stackoverflow.com/a/12379557/239657 |
|
/++ % Stack: (a) (b) => (ab) |
|
{ exch dup length |
|
2 index length add string |
|
dup dup 4 2 roll copy length |
|
4 -1 roll putinterval |
|
} bind def |
|
|
|
%%% Point-free style. |
|
|
|
/f { (foo of ) exch ++ } def |
|
/g { (goo of ) exch ++ } def |
|
/h_point_free { f g } def |
|
/h_inlined { (foo of ) exch ++ (goo of ) exch ++ } def |
|
|
|
%%% Local variables, PostScript's equivalent of functional "let" |
|
% Background: https://www-cdf.fnal.gov/offline/PostScript/BLUEBOOK.PDF |
|
% chapter 4 on dictionaries + cookbook "DICTIONARIES AND LOCAL VARIABLES" page 132 |
|
|
|
/f_locals % Stack: (s) => (foo of s) |
|
{ % Create a temp dictionary, sized for 1 word. |
|
1 dict |
|
% Push it on the dictionary stack, so "def" writes words into it |
|
% instead of global dict, and word lookup finds these definitions. |
|
begin |
|
% Pop argument from top of stack and put it into local named s: |
|
/s exch def |
|
|
|
(foo of ) s ++ |
|
% Pop the local dict from the dictionary stack |
|
end |
|
} def |
|
|
|
/g_locals % Stack: (s) => (goo of s) |
|
{ 1 dict begin |
|
/s exch def |
|
|
|
(goo of ) s ++ |
|
end |
|
} def |
|
|
|
/h_locals % Stack: (x) => (result) |
|
{ 3 dict begin |
|
/x exch def % name incoming argument |
|
/y (foo of ) x ++ def % name intermediate |
|
/z (goo of ) y ++ def % name intermediate |
|
z |
|
end |
|
} def |
|
|
|
%%% Not bad! But verbose. Could we define a "let" helper!? |
|
|
|
% Let's expect value before name, so we can use it on incoming argument already on stack. |
|
|
|
/let % Stack: value /name => ... |
|
% Dictionary stack: => locals |
|
{ 1 dict begin |
|
exch def |
|
% UNTERMINATED begin ! |
|
} def |
|
/endlet % Dictionary stack: locals => |
|
{ end } def |
|
|
|
/h_let % Stack: (x) => (result) |
|
{ /x let |
|
(foo of ) x ++ |
|
/y let |
|
(goo of ) y ++ |
|
/z let |
|
z |
|
endlet |
|
endlet |
|
endlet |
|
} def |
|
|
|
% Oh, well. Works but more verbose than /h_locals. |
|
|
|
%%% Defining "lambda" !?! |
|
|
|
% Would like: |
|
% /x { 5 x sub } lambda |
|
% to be equivalent to: |
|
% { exch 5 sub } |
|
|
|
/lambda % Stack: /name proc => proc |
|
{ /body let |
|
/name let |
|
% Conceptually, we want to build a proc (aka executable array) like: |
|
% { $name let $body exec endlet } |
|
% where $name and $body should vary, so can't use `{ ... }`. |
|
% `[ ... ]` builds an array from computed values, `cvx` marks it executable. |
|
% Non-varying words all have to be quoted with `/... cvx`. |
|
% See https://codesync.global/media/a-postscript-to-functional-geometry/ |
|
% for good fast tutorial on PostScript meta-programming, from ~20:00. |
|
[ name |
|
/let cvx |
|
% Just writing `body` would execute it. We want it as a value. |
|
/body load |
|
/exec cvx |
|
/endlet cvx |
|
] cvx |
|
%pstack |
|
endlet |
|
endlet |
|
} def |
|
|
|
% TODO: I suspect I've implemented dynamic scoping, not real lexical scoping? |
|
|
|
/f_lambda /s { (foo of ) s ++ } lambda def |
|
/g_lambda /s { (goo of ) s ++ } lambda def |
|
/h_lambda % Stack: (x) => (result) |
|
/x { |
|
(foo of ) x ++ |
|
/y { |
|
(goo of ) y ++ |
|
/z { |
|
z |
|
} lambda exec |
|
} lambda exec |
|
} lambda def |
|
|
|
% Well, the postfix placement of "lambda" itself is hard to read to my taste. |
|
% But so are all PostScript control structures :-) |
|
|
|
%%% Test them all |
|
|
|
(Hello!) h_point_free |
|
(Hello!) h_inlined |
|
% A "concatenative" language means we can also write it flatly without any procedures: |
|
(Hello!) (foo of ) exch ++ (goo of ) exch ++ |
|
|
|
(Hello!) f_locals g_locals |
|
(Hello!) h_locals |
|
|
|
(Hello!) h_let |
|
|
|
(Hello!) f_lambda g_lambda |
|
(Hello!) h_lambda |
|
|
|
% Do multi-arg lambdas work? Yes! |
|
|
|
/abab /b /a % Stack: (a) (b) => (abab) |
|
{ a b ++ a ++ b ++ |
|
} lambda lambda def |
|
|
|
(xx) (yy) abab |
|
|
|
pstack |