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

Re: Problems with "curry"'s formal specification

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


> Al wrote:
> The formal spec of curry is vague in a few respects:
> Why are "const"s called "constant"?  May they be any expressions?
> When is the procedure _expression_ evaluated?  When are the "constants"
> evaluated?  In other words, which of the following expressions are
> legal, and what do they return?
>   (let* ((x +) (y (curry x <> 1))) (set! x -)  (y 0))
>   (let* ((x 1) (y (curry + <> x))) (set! x -1) (y 0))
> The reference implementations give different results.

You raise a number of issues at the same time.
Let me address them in order.

1. Why are "const"s called "constant"?

The name was chosen because the values put into the
filled slots do not depend directly on the arguments
of the resulting procedure. As this is only true if
there are no common side effects, the name is not as
accurate as it appears at first sight. Unfortunately,
argument, parameter, and value are all very ambiguous
in this context. Do you have a suggestion?

2a. May they [the "constants", SE] be any _expression_?

Yes. They are only constant with respect to the slots.
For example, this is perfectly legal:

        (curry list <> (+ x 1))

2b. [...], which of the following expressions are legal, [...]?

Under the current specification, both are legal.

3a. When is the procedure _expression_ evaluated?
3b. When are the "constants" evaluated?
3c. [...], and what do they [the examples above, SE] return?

(These questions are also the issue raised by the
'cons-stream' example in your other posting with subject
line > Re: l, the ultimate curry that is not curry <)

Very good questions! The specification does not say,
and this is really a serious and dangerous omission
of this SRFI.

As background info, the original semantics was the one
produced by the hygienic and referentially transparent
macro implementation. This means, all expressions (proc
and consts) are evaluated at the time the specialized
procedure is being called. In your first example above,
one could replace "(curry x <> 1)" by "(lambda (a) (x a 1))"
using a text editor. The result of the entire example
will then be -1 because the value of the variable x
at the time it is referenced by the specialized procedure
is the subtraction function - and not addition function +.

When the procedural implementation came along, I became
slightly over-enthusiastic about the possibility to
implement the mechanism without macros---and forgot to
check the implications for the semantics. Thank you for
bringing the issue to my attention!

If curry is implemented as a procedure, the way it is
in the current 'macro-free' implementation, the variable
x will be referenced at the time (curry x <> 1) is evaluated.
In this case, the specialized procedure will always just
add one to its argument, and the example evaluates to 1.

So much for the analysis of the problem.
Now for some options to deal with it.

OPT1 There is the option to point out the problem and define
this aspect of the semantics unspecified. This means that
one should stay clear of instances like the ones you gave
because they are not necessarily portable. This option
looks more stupid than it really is. Recall that Scheme
(R5RS, Sect. 4.1.3) defines that the argument expressions
of a procedure call are evaluated in an unspecified order;
which allows examples in the style you gave (different
results for different implementations). Yet, this does not
do much harm in practice because we have all learned (I hope)
to avoid relying on a specific order in Scheme.

OPT2 Another option is to define the macro semantics as the
only SRFI-compliant semantics. In this case, it may be
hard to make a 'macro-free' implementation. The only
mechanisms in R5RS with non-strict evaluation are IF
and DELAY, and their derivatives. None of them is powerful
enough to cover the syntax of the SRFI, which is a pitty.

OPT3 Yet another option is to define the procedural semantics
as the only SRFI-compliant semantics. It is easy to modify
the macro implementation to evaluate the "constants" before
the specialized procedure is constructed. In this case, it
might be better to think about the mechanism as some form
of partial evaluation, without the tricky bit of really
doing it.

Whatever happens to the SRFI, this is certainly an issue
that has to be addressed. What is your advice?