Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.forth > #135643
| From | Lawrence D’Oliveiro <ldo@nz.invalid> |
|---|---|
| Newsgroups | comp.lang.forth, comp.lang.postscript, alt.folklore.computers, comp.lang.lisp |
| Subject | Re: Postscript in 4tH |
| Date | 2026-09-10 07:38 +0000 |
| Organization | A noiseless patient Spider |
| Message-ID | <117tmpa$1ov1u$1@dont-email.me> (permalink) |
| References | (3 earlier) <875x0gib1k.fsf@debian> <117prfv$gq7e$3@dont-email.me> <87o6e7cifh.fsf@debian> <117qido$ng8h$3@dont-email.me> <87h5jxagx6.fsf@debian> |
Cross-posted to 4 groups.
On Thu, 10 Sep 2026 01:06:45 -0300, Kragen Javier Sitaker wrote:
> Lawrence D’Oliveiro <ldo@nz.invalid> writes:
>>
>> On Tue, 08 Sep 2026 22:38:58 -0300, Kragen Javier Sitaker wrote:
>>>
>>> PostScript does in fact have something like readmacros; in
>>> particular, readhexstring was the recommended way to handle image
>>> data, so that the image data didn’t have to be loaded into a
>>> PostScript object by way of the PostScript parser. >> >> It’s just
>>> a function. It’s like saying Python has “readmacros” because >>
>>> the JSON and XML library modules have functions for reading input
>
> It’s a function that runs while the PostScript source code is being
> read, which means that it can change the interpretation of that
> source code.
>
> You’d have to be able to write something in Python which gave you a
> session like this:
>
> $ python3
> Python 3.11.2 (main, Aug 26 2024, 07:20:54) [GCC 12.2.0] on linux
> Type "help", "copyright", "credits" or "license" for more information.
> >>> from somemodule import typeof
> >>> typeof(oagjijgw) # or ideally even without the parentheses
> <ast.Name object at 0x7f52bb870130>
>
> I claim that this `typeof` function is impossible to write in
> Python, because the parser throws a NameError before `typeof` has a
> chance to run, given that I haven’t defined `oagjijgw` previously.
How about this little program:
import code
import ast
class TypeofExpander(ast.NodeTransformer) :
def visit_Call(self, node) :
result = node
if isinstance(node.func, ast.Name) and node.func.id == "typeof" :
result = ast.Constant(value = type(node.args[0]).__name__)
else :
result = type(node) \
(
func = node.func,
args = list(self.visit(a) for a in node.args),
keywords = list((a.arg, self.visit(a.value)) for a in node.keywords)
)
#end if
return result
#end visit_Call
def visit_Expr(self, node) :
return type(node)(self.visit(node.value))
#end visit_Expr
#end TypeofExpander
console = code.InteractiveConsole()
while True :
line = input("? ")
syntax_in = ast.parse(line, mode = "single")
syntax_out = TypeofExpander().visit(syntax_in)
ast.fix_missing_locations(syntax_out)
code = compile(syntax_out, filename = "<console>", mode = "single")
console.runcode(code)
#end while
Example run:
ldo@theon:python_try> ./readmacro_fakeit
? 2 + 2
4
? import math
? math.log
<built-in function log>
? typeof(oagjijgw)
'Name'
? print("typeof(", oagjijgw, ") is", typeof(oagjijgw))
Traceback (most recent call last):
File "<console>", line 1, in <module>
NameError: name 'oagjijgw' is not defined
? print("typeof(oagjijgw) is", typeof(oagjijgw))
typeof(oagjijgw) is Name
? print("typeof(", math.log, ") is", typeof(math.log))
typeof( <built-in function log> ) is Attribute
>> Homoiconicity comes in because the function body is stored in an
>> array object, which is a PostScript language type, and its contents
>> are also objects of various PostScript language types.
>
> The analogous statements were true of most Lisps in 01982, because
> `lambda` was basically implemented as `quote` when it was the
> argument of a function (or subr), but they are true of almost no
> other programming languages except assembly language, so this is
> another similarity between PostScript and Lisp.
Except that ...
> However, the analogous statements are not true of most current
> Lisps, which have adopted the position that lambda-expressions are
> lists, and functions are not lists.
So this is no longer a similarity between PostScript and Lisp.
> Perhaps you would argue that PostScript is homoiconic and SBCL and
> Racket are not. However, most people who know the word do consider
> them to be homoiconic, because, even though the *runtime
> representation* of functions does not contain objects of various
> Lisp language types, the *source code* is just a Lisp list, so
> building Lisp code in Lisp is easy:
OK, so the definition of “homoiconic” becomes “the AST *can* be
represented in terms of language objects”, not “the AST *is*
represented in terms of language objects”. I can accept that.
> Unfortunately, this definition of homoiconicity suggests that any
> language compiled from sequences of characters is “homoiconic”
> unless for some reason it lacks the ability to manipulate sequences
> of characters.
I don’t see why that should be “unfortunate” for the definition (for
the language -- that’s another matter). But I think a sequence of text
characters is too low-level and unstructured a representation to be
worthy of the name “homoiconic”, anyway. It definitely has to involve
the AST level in some way.
> But, look again at PG’s explanation of what he means by “a function
> type”:
>
>>> “In Lisp, functions are first class objects-- they’re a data type
>>> just like integers, strings, etc, and have a literal
>>> representation, can be stored in variables, can be passed as
>>> arguments, and so on.”
>
> The only one of these that plausibly relates to homoiconicity is
> “have a literal representation”. In old Lisps you could just print
> out the definition of any function as an S-expression, but, as we
> see above with Racket, that is not currently the case; we get
> something like `#<FUNCTION (LAMBDA ()) {534960EB}>` or
> `#<procedure>`. But that’s still a string representation! And *most*
> languages don't have the ability to print out, for example, struct
> literals.
Python can. If your class defines a method called “__repr__”, it will
be called by the built-in repr() function, and is expected to return
some string representation that should be usable to reconstruct the object.
Then there is also the “__str__” method and and corresponding built-in
str() function, which is just expected to return some convenient,
reasonably descriptive string.
>> Where PostScript is lacking is in missing support for lexical
>> binding. Anybody who has done much PostScript programming knows how
>> awkward it is to simulate anything resembling local variables.
>
> This is another similarity between PostScript and the then-popular
> Lisps, which almost entirely used dynamic scope like PostScript,
> rather than lexical scope like almost all other programming
> languages. However, it is true that the facility is more convenient
> to use in Lisp.
>
> Here’s a slightly reformatted interactive session showing how
> awkward it is to simulate anything resembling local variables, in
> case anyone is curious:
>
> ...
>
> This is definitely more awkward than in most languages, but it
> doesn’t seem prohibitive to me.
For comparison, here’s an example from my PostScript-alike:
/Count 99 ddef
/metatry
{ # provides context for nonlocals
dup
/Name exch ldef
/Count 0 ldef
{ # actual proc
/Count dup lload 1 add lstore
/Count dup dload 1 add dstore
Name =
(local Count = ) print /Count lload =
(global Count = ) print /Count dload =
(whichever Count = ) print Count =
}
}
ddef
/try1 metatry ddef
/try2 metatry ddef
try1
try2
try1
try2
Note the use of ldef/lload/store for lexical binding, and
ddef/dload/dstore for dynamic binding, in place of simple
def/load/store in old PostScript. As a result, functions now actually
become useful as first-class objects. The output is:
try1
local Count = 1
global Count = 100
whichever Count = 1
try2
local Count = 1
global Count = 101
whichever Count = 1
try1
local Count = 2
global Count = 102
whichever Count = 2
try2
local Count = 2
global Count = 103
whichever Count = 2
>>> 7. A symbol type. [...]
>>
>> True enough.
>>
>> Java has the option for “interned” strings, which is a way of having a
>> symbol type without having a symbol type, if you like.
>
> That’s true, and in particular that’s useful if you’re implementing some
> kind of language parser or interpreter in Java. Python has this too.
Python doesn’t need it, because simple “==” equality comparison works
anyway, whereas it doesn’t in Java.
>>> 8. A notation for code using trees of symbols. Yes. The only
>>> difference is that in conventional Lisp they’re binary trees, while
>>> in PostScript they’re N-ary ordered trees.
>>
>> In Lisp, the tree structure is apparent in the static syntax. In
>> PostScript, the tree structure (such as it is) gets largely
>> constructed dynamically at run time, and need not correspond to
>> static syntax at all.
>
> I’m not sure I agree. Here’s my example of tree-structured code in
> PostScript, from the previous post:
>
> GS>/sign {dup 0 gt {pop /positive} {0 lt {/negative} {/zero} ifelse} ifelse} def
>
> This is an executable array of six things, the fourth of which is `{pop
> /positive}`. To me, that’s *more* apparent from the static syntax than
> the fact that in `(lambda (x y) (sqrt (+ (* x x) (* y y))))` the car of
> the car of the cdr of the cdr is `sqrt`.
I said “need not correspond”, not “does not correspond”. Just because
you can write structures statically in PostScript doesn’t mean you
have to.
>> I remember doing some experiments with an Apple LaserWriter and a
>> Macintosh II back in the late 1980s. Someone had cracked the
>> encryption of the “eexec” operator, and we used this to discover
>> that there was this other thing called “cexec” (only allowed within
>> encrypted “eexec” execution, which is why you never saw it in
>> public code) that let you load MC68000 machine code into the
>> printer and hook into an API provided by the PostScript interpreter
>> to manipulate PostScript objects and make function calls.
>
> Wow, that’s amazing! I only ever knew that there was some
> controversy about extracting fonts. Maybe this is how it was done?
There are PostScript functions called “charpath” and “pathforall”. The
former lets you add a piece of text as outlines to the current path,
instead of directly rendering it. Then you can create special effects
with the usual filling and stroking operators. “pathforall” is a way
to traverse the current elements of the path, invoking suitable
callbacks for each. In PostScript level 1, the path was locked against
traversal if it contained any outlines generated from Adobe’s
proprietary Type 1 fonts.
This restriction was (mostly) lifted in PostScript level 2.
Back to comp.lang.forth | Previous | Next — Previous in thread | Next in thread | Find similar | Unroll thread
Postscript in 4tH Hans Bezemer <the.beez.speaks@gmail.com> - 2026-09-05 19:55 +0200
Re: Postscript in 4tH Paul Rubin <no.email@nospam.invalid> - 2026-09-05 15:54 -0700
Re: Postscript in 4tH albert@spenarnc.xs4all.nl - 2026-09-06 11:08 +0200
Re: Postscript in 4tH Paul Rubin <no.email@nospam.invalid> - 2026-09-07 09:24 -0700
Re: Postscript in 4tH albert@spenarnc.xs4all.nl - 2026-09-07 23:47 +0200
Re: Postscript in 4tH Kragen Javier Sitaker <kragen@canonical.org> - 2026-09-08 02:09 -0300
Re: Postscript in 4tH Lawrence D’Oliveiro <ldo@nz.invalid> - 2026-09-08 20:34 +0000
Re: Postscript in 4tH Kragen Javier Sitaker <kragen@canonical.org> - 2026-09-08 22:38 -0300
Re: Postscript in 4tH Lawrence D’Oliveiro <ldo@nz.invalid> - 2026-09-09 03:05 +0000
XML in Pythong (was: Re: Postscript in 4tH) Johann 'Myrkraverk' Oskarsson <johann@myrkraverk.invalid> - 2026-09-09 15:00 +0800
Re: Postscript in 4tH Kragen Javier Sitaker <kragen@canonical.org> - 2026-09-10 01:06 -0300
Re: Postscript in 4tH Lawrence D’Oliveiro <ldo@nz.invalid> - 2026-09-10 07:38 +0000
Re: Postscript in 4tH Peter Flass <Peter@Iron-Spring.com> - 2026-09-10 07:39 -0700
Re: Postscript in 4tH antispam@fricas.org (Waldek Hebisch) - 2026-09-15 16:04 +0000
Re: Postscript in 4tH Paul Rubin <no.email@nospam.invalid> - 2026-09-15 09:24 -0700
Re: Postscript in 4tH Johann 'Myrkraverk' Oskarsson <johann@myrkraverk.invalid> - 2026-09-09 15:15 +0800
Re: Postscript in 4tH Kragen Javier Sitaker <kragen@canonical.org> - 2026-09-10 01:11 -0300
Re: Postscript in 4tH anton@mips.complang.tuwien.ac.at (Anton Ertl) - 2026-09-09 07:35 +0000
Re: Postscript in 4tH Lawrence D’Oliveiro <ldo@nz.invalid> - 2026-09-09 08:10 +0000
Re: Postscript in 4tH Hans Bezemer <the.beez.speaks@gmail.com> - 2026-09-10 17:58 +0200
Re: Postscript in 4tH Kragen Javier Sitaker <kragen@canonical.org> - 2026-09-10 01:44 -0300
Re: Postscript in 4tH Paul Rubin <no.email@nospam.invalid> - 2026-09-09 03:01 -0700
Re: Postscript in 4tH albert@spenarnc.xs4all.nl - 2026-09-09 14:05 +0200
Re: Postscript in 4tH anton@mips.complang.tuwien.ac.at (Anton Ertl) - 2026-09-09 06:42 +0000
Re: Postscript in 4tH Lawrence D’Oliveiro <ldo@nz.invalid> - 2026-09-09 08:28 +0000
Re: Postscript in 4tH anton@mips.complang.tuwien.ac.at (Anton Ertl) - 2026-09-09 10:03 +0000
Re: Postscript in 4tH Lawrence D’Oliveiro <ldo@nz.invalid> - 2026-09-09 22:17 +0000
Re: Postscript in 4tH albert@spenarnc.xs4all.nl - 2026-09-09 14:42 +0200
Re: Postscript in 4tH antispam@fricas.org (Waldek Hebisch) - 2026-09-09 19:17 +0000
Re: Postscript in 4tH albert@spenarnc.xs4all.nl - 2026-09-10 12:22 +0200
Re: Postscript in 4tH Lawrence D’Oliveiro <ldo@nz.invalid> - 2026-09-09 21:54 +0000
Re: Postscript in 4tH Paul Rubin <no.email@nospam.invalid> - 2026-09-09 22:14 -0700
Re: Postscript in 4tH albert@spenarnc.xs4all.nl - 2026-09-10 12:30 +0200
Re: Postscript in 4tH albert@spenarnc.xs4all.nl - 2026-09-09 14:36 +0200
Re: Postscript in 4tH Hans Bezemer <the.beez.speaks@gmail.com> - 2026-09-06 14:27 +0200
Re: Postscript in 4tH Hans Bezemer <the.beez.speaks@gmail.com> - 2026-09-08 17:18 +0200
csiph-web