| Well it seems that OP needn’t bother as this problem is already solved. You wrote (loop (print (eval (read)))). How does that go with a screen reader? Like: Bracket loop bracket print bracket eval bracket read bracket bracket bracket bracket? The key thing I think is balancing and shifting parens. (loop (print (eval)) (read))
Is quite hard to sound different from (loop (print (eval (read))))
And more crucially what about the difference between these two: (let ((x (f))) (g x) (g x))
(let ((x (f)) (g x)) (g x))
(I think writing these on a single line makes them written more like they might be spoken)On the other hand I think being able to modify the syntax structurally is a big advantage. Going back to the topic of the OP I think a useful thing is putting functions after their arguments, and optimising to have single arguments or most non-main arguments being typically small. For example something more like read
| eval
| print
| loop
And maybe some way to do arguments like read stdin
| eval some-environment
| print :pretty
| loop
|
A screen reader need not literally read what’s on screen. It typically doesn’t with prose, where punctuation isn’t spoken, but affects timing and intonation, and abbreviations often are expanded (iOS speaks “Dr. John St.” as “Doctor John Street”, for example, but “St. John Dr.” as “Saint John dee-ar”. MacinTalk used to know that ‘Dr’ means ‘Drive’)
So, it need not do that here, and could say
“call read, eval it, print the result, and call loop on print’s output”
, using intonation or voice to indicate the difference between content read from the screen and text describing it.
Farfetched? Maybe, but take a look at what screen readers do with html.
A screen reader that knows lisp semantics could go even further, and replace loop by repeat forever or something like it.