[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Countering the counter-proposal

This page is part of the web mail archives of SRFI 10 from before July 7th, 2015. The new archives for SRFI 10 contain all messages, not just those from before July 7th, 2015.

> Using `#,' in a program has two effects: it causes side effects to
> occur at read time and it ensures that a form is evaluated only once.
> The first has questionable utility and semantics.  The second is
> already available in R5RS as `delay' and `force'. 

I have come across a counter-example to the last statement.

do ((i 0 (+ 1 i))) ((>= i 5))
    (let ((b (list (force (delay (begin (display "in form\n") 1 ))))))
      (display b) (newline)))
in form
in form
in form
in form
in form

(include "myenv.scm")
(include "read-apply.scm")
(define-reader-ctor 'form (lambda () (display "in form\n") 1)) 

(do ((i 0 (+ 1 i))) ((>= i 5))
   (let ((b (list #,(form))))
      (display b) (newline)))
in form

This shows that #,(ctor) has quite a different semantics than (force
(delay (ctor)). The latter can be evaluated several times if occurs
within a special form. The #,(ctor) expression is _really_ evaluated
only once - when it is read. This counter-example appears to
invalidate the counter-proposal and its discussion.

	It is instructive however to look into differences between
#,(ctor) and (force (delay (ctor)) further. The former evaluates at
read-time. By the time compiler/interpreter comes across #,(ctor), the
latter will be substituted by a _constant_ expression. A special form
will never see  #,(ctor) as it is -- it will see a constant. In
contrast, (force (delay (form)) within a special form will appear as
an expression, which cannot be tested at macro-expansion time, is not
eligible for const-folding, etc. Sergei Egorov was right that "It's a
pity that this [counter-proposal] form won't work inside
quoted constants, though." I should add that the counter-proposal
"will not work" within any syntax form (quote being one of them).

> I could get the same effect in vanilla R5RS, with much more power
> and flexibility, by using EVAL and an extensible reader:
>   (define my-reader (make-reader ...))
>   (eval (my-reader filename) some-environment)

I would like to dispute this statement as well. The first problem is
which 'some-environment' do you pass to eval? If it is an
(scheme-report-environment 5), a form read from the 'filename' may not
refer to procedures other than those in R5RS. Even if the parent
program defines a custom constructor for uniform vectors (per SRFI-4),
the 'filename' may not refer to it as it is not a part of R5RS. If the
'some-environment' stands for an interaction-environment the parent
then program tacitly permits the 'filename' to apply any function
defined in the parent program -- even such dangerous functions as
OS:system or OS:unlink if the current interaction-environment happens
to define them. You really don't want to do that. In any case this is
an "all-or-nothing" proposition. SRFI-10 devotes a special paragraph
to these issues (see a "Comparisons" subsection). Note R5RS does not
define any function to manipulate 'eval-environment's.

	Another problem with the eval-solution above is that it
contains "eval". SRFI-10 does not require a Scheme reader to perform
an evaluation of arbitrary expressions. SRFI-10 merely specifies that
the reader should be able to locate a constructor-procedure and apply
it to arguments. BTW, nowhere does SRFI-10 tell that the constructor
is a Scheme function; it can be written in any language as long as the
reader is able to invoke it passing appropriate parameters. For
example, one can write a Scheme->foo _compiler_ in ML and implement
reader-constructors as ML functions.

	The biggest problem with the above eval-solution  is that it
assumes that the form read from a file is an expression to be
evaluated. Suppose the file contains a string
	"(1 2 #,(f32 1.0 2.0))"
How can you pass the result of reading of this string to eval? All the
counter-example discussion tacitly assumes that the form being read is
a code form. But one can use a 'read' procedure to read arbitrary
data. For example, one can use read to load "persistent" data; or to
read information sent over communication channels. It has to be
stressed that not every Scheme object has a readable representation
(structures and records spring to mind). Furthermore, not every R5RS
object can be written (and then reloaded): for example, cyclical lists
and other data structures with circular dependencies, data structures
with large caches or memoization tables, etc. SRFI-10 proposes a way
to define a custom loader -- the only extension to the Scheme reader
that will be necessary to solve an immense number of problems.