X-Received: by 10.68.194.97 with SMTP id hv1mr12061491pbc.0.1425027589646; Fri, 27 Feb 2015 00:59:49 -0800 (PST) X-Received: by 10.182.60.196 with SMTP id j4mr100340obr.33.1425027589422; Fri, 27 Feb 2015 00:59:49 -0800 (PST) Path: csiph.com!v102.xanadu-bbs.net!xanadu-bbs.net!news.glorb.com!hl2no33374086igb.0!news-out.google.com!qk8ni43839igc.0!nntp.google.com!hl2no33374078igb.0!postnews.google.com!glegroupsg2000goo.googlegroups.com!not-for-mail Newsgroups: comp.lang.postscript Date: Fri, 27 Feb 2015 00:59:49 -0800 (PST) In-Reply-To: <20141116013757.0dacc25d@samara.DOMA> Complaints-To: groups-abuse@google.com Injection-Info: glegroupsg2000goo.googlegroups.com; posting-host=108.86.113.216; posting-account=G1KGwgkAAAAyw4z0LxHH0fja6wAbo7Cz NNTP-Posting-Host: 108.86.113.216 References: <20141030172728.0983c6bc@samara.DOMA> <95798773-17c6-41d3-8d80-06d1784a7e95@googlegroups.com> <20141102001537.515de3e5@samara.DOMA> <1cc8e78b-6698-4bab-b63c-9475cc63a5c3@googlegroups.com> <20141116013757.0dacc25d@samara.DOMA> User-Agent: G2/1.0 MIME-Version: 1.0 Message-ID: <52999eef-98fd-429f-ad2d-e76b779edbed@googlegroups.com> Subject: Re: map and higher order functions From: luser- -droog Injection-Date: Fri, 27 Feb 2015 08:59:49 +0000 Content-Type: text/plain; charset=ISO-8859-1 Xref: csiph.com comp.lang.postscript:2194 On Saturday, November 15, 2014 at 6:38:00 PM UTC-6, Carlos wrote: > [luser- -droog , 2014-11-15 00:43] > [...] > > There is a possible problem here. Since `bind` applies to all > > subarrays, and the user-proc has been embedded directly into this > > array. > > > > instead of > > > > > //proc exec > > > > it might be better to do > > > > //mydict /proc get exec > > > > so the procedure is not directly embedded. > > > > Applying `bind` would break code that tries to use operator names as > > variables, like > > > > { > > /length 5 def > > length dup mul % length^2 > > ... > > } > > > > The executable name `length` in the second line would be replaced by > > the postscript operator if `bind` were applied. > > I didn't think of that. The problem is worse, because the string is > tokenized at the time /map is executed, and by that moment the user > could have already redefined some operators (presumably he wouldn't do > that at library loading time). > > /length 5 def [ 1 2 3 ] { length add } map > > So, basically, inside /map, the code surrounding " exec" > should be bound before any operator is redefined, but the "" > should be left as-is. > > One solution can be to write the code as usual (not in a string), using > placeholders for the objects. That way, it would be bound at definition > time. When /map is called, the placeholders are replaced with the > objects. Basically, doing the "({ //x }) token" thing by hand, just so > everything that isn't a //name can be bound at definition time. > > Here is a new version of map that uses that approach, plus two helper > procedures: > > % map > /map { > 4 dict begin > /,proc exch def > /,arr exch def > /,res ,arr length > ,arr type /stringtype eq { string } { array } ifelse > def > /,i 1 array def > { > 0 1 /,arr length 1 sub { % for > dup /,i 0 3 -1 roll put > /,arr exch get > /,proc exec > /,res /,i 0 get 3 -1 roll put > } for > /,res > } deepcopy dup currentdict replaceall > end exec > } bind def > > % copies array recursively > % deepcopy > /deepcopy { > dup xcheck exch > dup length array copy > dup length 1 sub 0 exch 1 exch { % for % a i > 2 copy 2 copy get dup type /arraytype eq % a i a i e ? > { % ifelse > deepcopy put > } > { > pop pop pop > } ifelse > pop > } for > exch { cvx } if > } bind def > > % recursively replaces elements in found in > % replaceall - > /replaceall { > 1 index length 1 sub 0 1 3 -1 roll { % for 0 1 length-1 > 3 copy 3 -1 roll exch % a d i d a i > get % a d i d e > 2 copy known % a d i d e ? > % ifelse > { % a d i d e > get % a d i v > 3 index 3 1 roll % a d a i v > put > } % else > { % a d i d e > dup type /arraytype eq % a d i d e ? > { exch replaceall } > { pop pop } ifelse > pop > } ifelse % a d > } for > pop pop > } bind def > > Carlos. > -- I stumbled across an old one of mine. The file is dated Dec 24 2012. This version is not safe to use if any of its operators are not available by their standard names at *execution time*, ie. this code exhibits the problem that Carlos's code solves. But it's shorter. :) It also modifies the argument in-place. So if you want a copy, make a copy. Delayed-binding, and such. %! %/exch{pstack exch}bind def %string proc map -- %array proc map -- /map{ 4 dict dup begin {/dic/proc/src}{exch def}forall 0 1 src length 1 sub ( { //dic/i 2 index put //src exch get //proc exec //src exch //dic/i get exch put } )token pop exch pop bind end for }def [1 1 1]dup{1 sub}map == (---)== flush (this_is_a_lowercase_string___ish)dup {16#20 sub}map ==