SRFI 232: An advanced currying form Arthur A. Gleckler (08 Jan 2022 02:21 UTC)
Re: SRFI 232: An advanced currying form Dr. Arne Babenhauserheide (08 Jan 2022 17:24 UTC)
Re: SRFI 232: An advanced currying form Marc Nieper-Wißkirchen (08 Jan 2022 18:26 UTC)
Re: SRFI 232: An advanced currying form Wolfgang Corcoran-Mathe (09 Jan 2022 18:45 UTC)
Re: SRFI 232: An advanced currying form Marc Nieper-Wißkirchen (09 Jan 2022 21:56 UTC)
Re: SRFI 232: An advanced currying form Wolfgang Corcoran-Mathe (13 Jan 2022 22:37 UTC)
Re: SRFI 232: An advanced currying form Marc Nieper-Wißkirchen (14 Jan 2022 07:24 UTC)
Re: SRFI 232: An advanced currying form Wolfgang Corcoran-Mathe (18 Jan 2022 19:30 UTC)
Re: SRFI 232: An advanced currying form Marc Nieper-Wißkirchen (19 Jan 2022 00:44 UTC)
Re: SRFI 232: An advanced currying form John Cowan (16 Jan 2022 18:29 UTC)
Re: SRFI 232: An advanced currying form Marc Nieper-Wißkirchen (16 Jan 2022 18:52 UTC)
Re: SRFI 232: An advanced currying form Marc Nieper-Wißkirchen (16 Jan 2022 19:01 UTC)
Re: SRFI 232: An advanced currying form John Cowan (20 Jan 2022 06:21 UTC)
Re: SRFI 232: An advanced currying form Wolfgang Corcoran-Mathe (18 Jan 2022 18:28 UTC)
Re: SRFI 232: An advanced currying form Wolfgang Corcoran-Mathe (18 Jan 2022 18:38 UTC)
Re: SRFI 232: An advanced currying form Marc Nieper-Wißkirchen (18 Jan 2022 19:00 UTC)
Re: SRFI 232: An advanced currying form Wolfgang Corcoran-Mathe (18 Jan 2022 21:22 UTC)
Re: SRFI 232: An advanced currying form Marc Nieper-Wißkirchen (18 Jan 2022 22:18 UTC)
Re: SRFI 232: An advanced currying form Marc Nieper-Wißkirchen (19 Jan 2022 07:47 UTC)
Re: SRFI 232: An advanced currying form Marc Nieper-Wißkirchen (19 Jan 2022 20:55 UTC)
Re: SRFI 232: An advanced currying form Wolfgang Corcoran-Mathe (24 Jan 2022 23:08 UTC)
Re: SRFI 232: An advanced currying form Marc Nieper-Wißkirchen (26 Jan 2022 13:29 UTC)
Re: SRFI 232: An advanced currying form Wolfgang Corcoran-Mathe (31 Jan 2022 21:42 UTC)
Re: SRFI 232: An advanced currying form Dr. Arne Babenhauserheide (09 Jan 2022 01:35 UTC)
Re: SRFI 232: An advanced currying form John Cowan (16 Jan 2022 18:15 UTC)
Re: SRFI 232: An advanced currying form Wolfgang Corcoran-Mathe (09 Jan 2022 18:47 UTC)

Re: SRFI 232: An advanced currying form Marc Nieper-Wißkirchen 09 Jan 2022 21:56 UTC

Am So., 9. Jan. 2022 um 19:45 Uhr schrieb Wolfgang Corcoran-Mathe
<xxxxxx@sigwinch.xyz>:
>
> Hi Marc, and thanks for commenting.
>
> First of all, having read your thoughts, I suggest that we not throw
> the baby out with the bath-water.  The current version of this form
> is not fixed, of course, and I think we can improve it.

Yes; I'm sorry if it sounded too much like it.

> On 2022-01-08 19:26 +0100, Marc Nieper-Wißkirchen wrote:
> > Guile's lambda* seems to come from SRFI 89's lambda*. I agree with
> > Arne that a different name should be chosen for SRFI 232.
>
> Yes.  As hinted in the Issues, I think lambda* is a pretty awful
> name.  I'd like to hear some alternative suggestions.  Here
> are a few off-the-cuff possibilities:
>
> * lambda-c
> * curry (unfortunately, used by lots of other similar macros)
> * kappa (from 'Kurry')

As Scheme nowadays usually supports Unicode, schönfinkel or
шейнфинкель would be better than curry. But certainly not optimal. :)

I would postpone this discussion (which is bike-shedding at this
point) until the semantics of the new form(s) have been fixed.

> As for the define sugar, how about define-curried ?
>
> > (1) Do we really need to make this type of currying easier in Scheme?
> > ...
> > I would like to see a real-world use case where the
> > proposed form actually makes the resulting code easier to understand
> > (and to write).
>
> I'm not sure I understand what you mean by "this type of currying".

Partially applying the first arguments to a procedure on the one hand,
and applying excess arguments to a procedure result.

> Do you mean the way that lambda* allows procedures to be applied to
> fewer or more arguments than they accept, as opposed to the "fixed"
> currying of SRFI 219?

SRFI 219 does not have the flaws I described under point (2). But SRFI
219 does not really have much to do with SRFI 232, does it? SRFI 219
just introduces some syntactic sugar (which I think is superfluous and
which others think is important enough to have in a standard).

> I agree that I'd like to see useful examples of lambda*, and I believe
> that the sum/product example given in the SRFI is one, though it's
> tiny.

I think the sum and product examples are just examples coincidentally
because the fold procedure happens to take the list as its last
argument. They would better serve as motivating examples for SRFI 26.

That said, I still find (lambda (ls) (fold + 0 ls)) clearer than (cut
fold + 0 _), especially when reading code.

Moreover, the problem with fold* procedure is that lambda*/define*
does too much here: It happily accepts more than three arguments and
feeds the extra arguments into the result of fold (which could be a
procedure!), but this is usually not what we want in general. In a
language with dynamic typing, this can lead to hard-to-detect bugs and
replaces a helpful error message like "wrong number of arguments"
with, at best, "cannot apply blah to arguments".

Again, citing ML and Haskell here is not the right thing for Scheme
because ML and Haskell are strongly typed.

> In Haskell and other "curried languages", I very frequently
> write partially-applied expressions like "foldr + 0" or "map (+ 1)";
> this terseness and omitting of unneeded detail can dramatically
> simplify programs, I think.  (You can do this with cut, but the
> advantage of lambda* here is its extreme brevity and ordinary syntax.)

It is certainly subjective whether this simplifies programs. IMO, it
makes reading them harder and less Scheme-y. But that's, as I said,
subjective.

What would be the semantics of a hypothetical +* in Scheme be?

And would you want to define "curried" (lambda*) versions of the
standard procedures of Scheme? You certainly don't want the regular
fold to be defined via lambda*, for example, because it would be
slower (see below) and because people would suddenly see very
different errors (probably misleading) when they make a mistake and
call fold with the wrong number of arguments.

>> Whether this use is "real-world" is, of course, a matter of opinion.
> (https://xkcd.com/1312/ applies.)  But I suggest that the "real world"
> in programming is always a matter of opinion, so maybe we can find a
> different criterion of significance.

IMO, new syntactic abbreviations should only be standardized if they
either make things possible that would otherwise be awkward to do or
if they allow expressing some concept clearly and neatly. For
otherwise, if there are too many options, Scheme code written by one
person will be harder to understand by a second person.

> > (2) My biggest complaint about the lambda* form is that the behavior
> > is irregular. If I apply as many arguments as there are formals, it
> > would make as much sense to return a thunk. The arbitrariness at such
> > limit points is a source for future programming errors. Another
> > discontinuity is at the border between returning a value and applying
> > the excess arguments to the resulting values. While it looks elegant,
> > the lambda* form confounds three things.
>
> Am I understanding right that you think that lambda* is combining
> several different features in a way that makes its behavior
> unpredictable?  Can you identify the three things that you think
> it's "confounding"?

Not unpredictable, but logically not satisfactory.

> I think that there is some oddness in the treatment of nullary
> procedures and application to zero arguments, and the form may be
> tricky to reason about overall: lambda* does a lot.

As I wrote above about the fold* example, lambda* does too much (in general).

> As for applying a
> k-ary procedure to k arguments, I agree that it would make theoretical
> sense to return a thunk, but, practically, there's no
> question--applying the procedure makes far better sense to me

It may make more sense in most cases, but when reasoning about code or
introducing extra formal arguments later suddenly turning would-be
thunks (which are treated irregularly) into procedures with arguments
(which are treated regularly) or introducing extra actual arguments
later turning procedures taking arguments potentially into would-be
thunks, the illogic is problematic.

> Perhaps it's a contradiction of lambda*'s "zero arguments rule",
> though.  Can we make some improvements here?

You can introduce a form that creates procedures taking up to the
number of formal arguments and always returns a procedure. And it is a
mistake if more than the number of formal arguments are given.

A second form is needed (and should really be separate) for the second
case. Here, a procedure is created that takes at least the number of
formal arguments and always applies the access arguments to the
result. And it is a mistake if less than the number of formal
arguments are given.

> I think you meant "applying the resulting values to the excess
> arguments" in the second to last sentence, but maybe I've
> misunderstood.  While I wonder about possible problems that
> the extra-arguments behavior might introduce, I don't see
> any capriciousness here.  Regardless of whether a procedure is
> invoked on extra arguments, it *does* return a value.  If there
> are extra arguments, then this value is immediately invoked on
> them.

This discontinuity here is again the "thunk-case". Why shouldn't zero
arguments be applied to the result of the procedure when exactly the
right number of arguments are given?

>
> > (3) We need benchmarks on whether replacing lambda by lambda* affects
> > runtime (much) and whether calling the procedures resulting from
> > partially applying lambda* are as fast as hand-written procedures (or
> > those returned by SRFI 26).
>
> I've attached a very basic set of benchmark tests which use
> chibi's test library as a sloppy way to get execution times.  Each of
> the following entails 100,000 applications of a procedure; "normal"
> applies a 5-ary procedure, "hand-curried" applies a fully-curried
> 5-ary procedure, and the "lambda*" sets apply a 5-ary lambda*
> procedure through an increasing number of partial applications.
> See the attached file for details.
>
>     normal: .
>     1 out of 1 (100.0%) test passed in 0.015610933303833008 seconds.
>
>     hand-curried: .
>     1 out of 1 (100.0%) test passed in 0.09452295303344727 seconds.
>
>     lambda* coarsest: .
>     1 out of 1 (100.0%) test passed in 0.09674406051635742 seconds.
>
>     lambda* coarse: .
>     1 out of 1 (100.0%) test passed in 0.3158271312713623 seconds.
>
>     lambda* fine: .
>     1 out of 1 (100.0%) test passed in 0.728193998336792 seconds.
>
>     lambda* finest: .
>     1 out of 1 (100.0%) test passed in 0.9788308143615723 seconds.

Thanks for the prompt response and for writing the tests. A factor of
100 is a lot (while for Haskell it would be a factor of 1), but
currying 5 times may be a bit exaggerated. We would probably need some
real-world algorithm written in Haskell-liked curried form and written
in classical Scheme manner to test that.

Cheers,

Marc

>
> These were executed on a machine with a 4.2 GHz x86_64 processor
> and 8 GB RAM.  As usual with benchmarks, I advise not taking them
> very seriously.
>
> Best regards,
>
> --
> Wolfgang Corcoran-Mathe  <xxxxxx@sigwinch.xyz>
>
> "As Will Rogers would have said, 'There is no such thing as a
> free variable.'" --Alan J. Perlis