points by DonHopkins 4 years ago

>run-time interpretation need not apply

...because it can eval? ;)

>Why not just base everything on FEXPRs and force evaluation on the receiving side when needed?

PostScript is a lot like Lisp, where everything is an FEXPR. You pass around executable arrays to control flow functions like "if" and "for", and can write your own like "send".

NeWS used an object oriented programming system that was a lot like Smalltalk with multiple inheritance, which leveraged the PostScript dictionary stack so it was quite efficient. PostScript object references (independent of the object it points to) can be executable or literal. Code in PostScript is represented by executable arrays, executable names are looked up on the dictionary stack, and their corresponding values are executed (literal arrays and other objects are pushed, executable arrays have their elements executed in order, etc.)

As well as "send"ing an executable name to an object to execute a method by that name in its scope (by loading its instance/class/superclass/etc onto the dictionary stack), you could also "send" an executable array to an object to execute that code in the context of the object. (But that was not a common practice, just the way it happened to work because of how it was implemented.)

James Gosling's Emacs Mocklisp was like FEXPRs on PCP, with support for prompting the user to supply omitted arguments.

https://news.ycombinator.com/item?id=14312249

DonHopkins on May 10, 2017 | parent | context | favorite | on: Emacs is sexy

Hey at least Elisp wasn't ever as bad as Mock Lisp, the extension language in Gosling (aka UniPress aka Evil Software Hoarder) Emacs.

It had ultra-dynamic lazy scoping: It would defer evaluating the function parameters until they were actually needed by the callee (((or a function it called))), at which time it would evaluate the parameters in the CALLEE's scope.

James Gosling honestly copped to how terrible a language MockLisp was in the 1981 Unix Emacs release notes:

https://archive.org/stream/bitsavers_cmuGosling_4195808/Gosl...

    12.2. MLisp - Mock Lisp 

    Unix Emacs contains an interpreter for a language 
    that in many respects resembles Lisp. The primary 
    (some would say only) resemblance between Mock Lisp
    and any real Lisp is the general syntax of a program, 
    which many feel is Lisp's weakest point. The 
    differences include such things as the lack of a 
    cons function and a rather peculiar method of 
    passing parameters. 

"Rather peculiar" is an understatement. More info, links and code examples:

https://news.ycombinator.com/item?id=8727085

I was just recently writing about how PostScript is "homomorphicier" than Lisp, because it has a shorter more elegant Quine (but let's try not to think about BASIC):

https://news.ycombinator.com/item?id=29929367

Speaking of writing PostScript with PostScript, Stan also wrote an elegant PostScript Quine, which is even shorter than the Lisp Quine (PostScript is like a cross between Lisp and Forth, but homomorphic and more like Lisp actually -- but PostScript is even homomorphicier than Lisp because it has an even shorter Quine!):

https://www.donhopkins.com/home/archive/NeWS/news-tape/fun/q...

    Date: Thu, 14 Sep 89 20:29:28 -0400
    To: NeWS-makers@brillig.umd.edu
    Subject: A PostScript Quine
    From: spectral!sjs@bellcore.com  (Stan Switzer)

       "'Yields falsehood when preceded by itself in quotes" yields
       falsehood when preceded by itself in quotes." -- W. V. O. Quine
       (paraphrase)

    A "quine" is a program which when evaluated yields its own
    representation.  A quine can be formally described as a fixed point of
    a language's denotation function.  Trivial evaluations (e.g.:
    literals) are excluded and the program cannot require any input data
    (e.g.: "cat cat.c").

    In my experience, the merit of a language is inversely related to the
    length of its shortest quine.  (Though I _am_ prejudiced toward
    reflective semantics.)

    For the heck of it, let's say a PostScript quine is a procedure
    "{...}" which when followed by "n { exec } repeat" yields the same (or
    equivalent) value for any non-negative integer value of "n"
    (including 0).

    The shortest I have found for PostScript is

      {{[ exch /dup load /exec load ] cvx} dup exec}

    Compare to Lisp:

      ((lambda(f)(list f (list 'quote f))) '(lambda(f)(list f (list 'quote f))))

    or (ASCII) C:

      char*f="char*f=%c%s%c;main(){printf(f,042,f,042,012);}%c";main(){printf(f,042,f,042,012);}

    Not that it'll change your life or anything...

    Enjoy,

    Stan Switzer  sjs@bellcore.com

The only problem I have with Stan's theory about the merit of a language being inversely related to the length of its shortest Quine is the existence of "10 LIST" in BASIC, which is a decidedly un-meritorious language. But to its credit, DECSYSTEM 10 BASIC even has a "LISTREVERSE" command, which might be useful for implementing a Eniuq. For what it's worth, "10 LIST" and "10 LISTREVERSE" are also Line-by-Line Palendromic Quines, since single line programs are the same listed forwards and backwards. https://news.ycombinator.com/item?id=20007960

>LISTREVERSE and LISTNHREVERSE print the contents of the user's memory area in order of descending line numbers. LISTREVERSE precedes the output with a heading, LISTNHREVERSE eliminates the heading.

Stan now works at Adobe (of course, how could they NOT hire him after he wrote that beautiful PostScript Quine! ;) ):

https://www.linkedin.com/in/sjswitzer/

Homomorphism:

https://en.wikipedia.org/wiki/Homomorphism

Quine:

https://en.wikipedia.org/wiki/Quine_(computing)

HyperLook SimCity Demo Transcript: This is a transcript of a video taped demonstration of SimCity on HyperLook in NeWS.

https://donhopkins.medium.com/hyperlook-simcity-demo-transcr...

SimCity, Cellular Automata, and Happy Tool for HyperLook (nee HyperNeWS (nee GoodNeWS)): HyperLook was like HyperCard for NeWS, with PostScript graphics and scripting plus networking. Here are three unique and wacky examples that plug together to show what HyperNeWS was all about, and where we could go in the future!

https://donhopkins.medium.com/hyperlook-nee-hypernews-nee-go...

gumby 4 years ago

> PostScript is a lot like Lisp, where everything is an FEXPR. You pass around executable arrays to control flow functions like "if" and "for", and can write your own like "send".

TECO had that property too and it made it easy to write incomprehensible code (even for those of us who grokked the syntax)

  • DonHopkins 4 years ago

    So you're saying that Gosling's Emacs MockLisp was even more like the original TECO in Original Emacs than Gnu Emacs Lisp??!

bsder 4 years ago

> PostScript is a lot like Lisp, where everything is an FEXPR.

I view PostScript as a Forth rather than a Lisp. That may not be correct--as I'm by no means an expert in either.

> ...because it can eval? ;)

Perty much. :)

> It had ultra-dynamic lazy scoping: It would defer evaluating the function parameters until they were actually needed by the callee (((or a function it called))), at which time it would evaluate the parameters in the CALLEE's scope.

And that hits at one of the problems that Shutt hits in his thesis, dynamic default scope (aka global variables) interacts very badly with FEXPRs (and macros and lots of other things, too).

There is a reason why everybody abandoned dynamic scoping and went to lexical scoping as soon as memory got large enough. The problem of lexical scoping is that now you have to deal with the fact that your variables need a stack. The downside of lexical scoping is the memory consumption of holding the variable bindings as recursion proceeds--that kicks up a lot of garbage to be collected and complicates your name resolution data structure. This is why Scheme was so insistent on tail calls.

Shutt deals with the scoping ambiguity by keeping the references to the environments so they can be explicitly accessed as required. Thus, your "argument evaluator" can access the required environment. Do you need the environment of the original definition? You have that as an explicit variable. Do you need the current environment? You have that as an explicit variable. Most things are "lexical scope and argument evaluation", but they don't have to be. And that's important because, as we've found out over time, if you only have one or the other, some cases don't work. (ie. short-circuit "and" likely wants the "and" from the definition environment but wants to evaluate the arguments it chooses to evaluate in the current environment)

Of course, all that costs memory and CPU (especially GC!) cycles--both of which were in short-supply in 1980 and laughably abundant in 2010 (date of Shutt's thesis).