Email list hosting service & mailing list manager

make it so that (=? "hi" "hi") works Sandra Snan (25 May 2021 15:38 UTC)
Re: make it so that (=? "hi" "hi") works Marc Nieper-Wißkirchen (25 May 2021 15:55 UTC)
Re: make it so that (=? "hi" "hi") works Shiro Kawai (26 May 2021 00:57 UTC)
Re: make it so that (=? "hi" "hi") works John Cowan (26 May 2021 03:58 UTC)
Re: make it so that (=? "hi" "hi") works Marc Nieper-Wißkirchen (26 May 2021 06:08 UTC)
Re: make it so that (=? "hi" "hi") works Sandra Snan (26 May 2021 06:31 UTC)
Re: make it so that (=? "hi" "hi") works Marc Nieper-Wißkirchen (26 May 2021 06:35 UTC)
Re: make it so that (=? "hi" "hi") works Sandra Snan (26 May 2021 06:12 UTC)
Re: make it so that (=? "hi" "hi") works Marc Nieper-Wißkirchen (26 May 2021 06:31 UTC)
Re: make it so that (=? "hi" "hi") works Sandra Snan (26 May 2021 06:41 UTC)
Re: make it so that (=? "hi" "hi") works Marc Nieper-Wißkirchen (26 May 2021 06:49 UTC)
Re: make it so that (=? "hi" "hi") works Sandra Snan (26 May 2021 06:59 UTC)
Re: make it so that (=? "hi" "hi") works Marc Nieper-Wißkirchen (26 May 2021 07:10 UTC)
Re: make it so that (=? "hi" "hi") works Sandra Snan (26 May 2021 06:50 UTC)
Re: make it so that (=? "hi" "hi") works Marc Nieper-Wißkirchen (26 May 2021 07:09 UTC)
Re: make it so that (=? "hi" "hi") works Sandra Snan (26 May 2021 07:35 UTC)
Re: make it so that (=? "hi" "hi") works Marc Nieper-Wißkirchen (26 May 2021 07:48 UTC)
Re: make it so that (=? "hi" "hi") works Marc Nieper-Wißkirchen (26 May 2021 07:56 UTC)
Re: make it so that (=? "hi" "hi") works Sandra Snan (26 May 2021 08:13 UTC)
Re: make it so that (=? "hi" "hi") works Marc Nieper-Wißkirchen (26 May 2021 08:34 UTC)
Re: make it so that (=? "hi" "hi") works Sandra Snan (26 May 2021 08:55 UTC)
Re: make it so that (=? "hi" "hi") works Marc Nieper-Wißkirchen (26 May 2021 09:15 UTC)
Re: make it so that (=? "hi" "hi") works Sandra Snan (26 May 2021 10:27 UTC)
Re: make it so that (=? "hi" "hi") works Marc Nieper-Wißkirchen (26 May 2021 10:53 UTC)
Re: make it so that (=? "hi" "hi") works Sandra Snan (26 May 2021 12:15 UTC)
Re: make it so that (=? "hi" "hi") works Marc Nieper-Wißkirchen (26 May 2021 13:55 UTC)
Re: make it so that (=? "hi" "hi") works Sandra Snan (26 May 2021 14:32 UTC)
Re: make it so that (=? "hi" "hi") works Marc Nieper-Wißkirchen (26 May 2021 15:20 UTC)
Re: make it so that (=? "hi" "hi") works Sandra Snan (26 May 2021 17:02 UTC)
Re: make it so that (=? "hi" "hi") works Marc Nieper-Wißkirchen (26 May 2021 17:37 UTC)
Re: make it so that (=? "hi" "hi") works Marc Nieper-Wißkirchen (26 May 2021 17:48 UTC)
Re: make it so that (=? "hi" "hi") works Sandra Snan (26 May 2021 18:12 UTC)
Re: make it so that (=? "hi" "hi") works Sandra Snan (26 May 2021 18:20 UTC)
Re: make it so that (=? "hi" "hi") works Marc Nieper-Wißkirchen (26 May 2021 18:40 UTC)
Re: make it so that (=? "hi" "hi") works Sandra Snan (26 May 2021 19:06 UTC)
Re: make it so that (=? "hi" "hi") works Marc Nieper-Wißkirchen (26 May 2021 19:25 UTC)
Re: make it so that (=? "hi" "hi") works Sandra Snan (26 May 2021 19:38 UTC)

Re: make it so that (=? "hi" "hi") works Sandra Snan 26 May 2021 17:02 UTC

Marc Nieper-Wißkirchen <xxxxxx@nieper-wisskirchen.de> writes:
> It's also about idiomatic code. But I agree that whether this should
> influence the choice of names can hardly be resolved by technical arguments.

Which feels a bit unfair since you asked me to provide technical
arguments including performant implementation.

> When it denotes a hypothetical interface using your static dispatch
> system, it is as efficient as the latter when the compiler can deduce
> the types of x and y.

Or more so.

> Whether it is more efficient, depends (see above). But now I understand
> that you don't want (=? x y) to denote SRFI 128's (=? default-comparator x
> y) but something that is more like an extensible equal?.

Sure. But that is an implementation detail. My main concern is the
interface design. As the subject line says, I want (=? "hi" "hi") to
work.

> So let's forget about the latter

So what was the conclusion about that topic?

> and continue to talk about your new version of =?, which is based on
> some compile-time registry.

Correct. But it's pretty new and only tangentially related to this SRFI.
So we are veering into off-topic.

> The problem is that the same hash table would be erroneously shared between
> two different instances of a generic procedure whose names only differ
> because of hygienic renaming.

The same key entry, you mean?

The hash table is shared across all generic procedures defined with this
interface.

The procedure names (frob in this case) are decolored / syntax-stripped
and used as keys to this shared hash-table.

> Another problem

I wasn't clear on how that the preceding was a problem.

> not related to hygiene with your code is lexical scoping that would be
> violated:
>
> (define-generic (plus ...) ...)
> (f ...)
>
> (define (f ...)
>   (define-generic (plus ...) ...))

Yes, you are correct that this is a problem. The scope of the most
recent call to define-generic (for that specific procedure name) will be
used.

For example

(define (f ...)
 (define-generic (plus ...) ...)
 (define-generic (plus ...) ...))

is fine if all of the pluses are defined in that scope.

Errors can happen when they are defined in different scopes.

> I would say that scenarios B and C are mostly equivalent.

Yes. But, it's only in scenario B where you'd wanna slot in custom
comparators into =? in the first place. In other words, a kind of niche
and suboptimal scenario.

> Scenario B is just scenario C applied to a union type.

Yes, union types would be a better way to solve scenario B, which is why
I am much more concerned about scenario A, which is where you want an
extensible record of default types and their comparators.

> Your efficient implementation of (=? x y) has different semantics than
> (lambda (x y) (=? (make-default-comparator) x y)). The former implements
> scenario B/C; the latter implements scenario A. I am not convinced that
> scenario A is very important in practice.

And we are back to discussing the interface:

Is (=? x y)

(with some comparator registration or define-generic way to extend it)

a better interface that

(=? supply-comparator-here x y)

That's fine, discussing the interface is more interesting than
discussing the implementation, but, I also feel like everything's been
said there.

Another analogy is how print (which is nonstandard but it's basically
convert to strings, concatenate, and print with newline) and display
both default to (current-input-port) unless you supply a port.

Good, cozy design that a makes me as programmer happy.

> About the latter: Assume that we want to conceive a linear algebra package
> that can multiply matrices whose entries are elements of some ring but we
> want to make the algorithm generic with respect to this ring.
>
> One approach akin to SRFI 128's comparator approach is to specify a
> procedure like
>
> (matrix-* ring m1 m2)
>
> where ring is a value encapsulating the properties of the ground ring.
>
> The procedure matrix-* itself will call (ring-element-* ring e1 e2) at some
> point.
>
> Of course, no one would write (ring-element-* integer-ring 2 3) instead of
> (* 2 3), but for the purpose of writing the body of matrix-* having
> ring-element-* is essential.
>
> What would your alternative approach for such a library interface be?

((ring-element-* integer-ring) 2 3) of course.

(ring-element-* integer-ring) ⇒ *

(ring-element-* xyzzy-ring) ⇒ frobnicate

Alternatively, if you wanna do SICP style message passing case dispatch
instead of generics:

(integer-ring 'ring-element-*) ⇒ *

(xyzzy-ring 'ring-element-*) ⇒ frobnicate

((quotient-ring r i)  'ring-element-*) ⇒ (lambda (a b) (+ i (* a b)))

This is a good interface because we can then use maps, reduce etc to
implement our matrix operators, which we can't (directly) if
ring-element heterogenously contains the dispatching type record.

> Why should it be expensive to unpack the type record? Through
> constant-folding, the compiler may even be able to get rid of it altogether.

Because as I showed with my generics toy implementation it's possible to
instead completely unroll the record directly into cond clauses in the
environment.

> Anyway, I have one more question about your efficient version of =?: As
> your define-generic creates macros,

It creates procedures. Fully usable with map etc and exportable to
libraries and such.

> they won't affect previously expanded code like code loaded earlier
> from libraries. How can you then make sure that a generic frobnicator
> knows about your monster sprites?

That's a good catch, since the type record is reset when define-generic
is loaded from a library. It won't remember previous definitions to the
same generic. The generics, with this particular implementation of
generics, all need to be defined at the same time in the same scope.

That's a good catch.

Here is a workaround:

Say I import a frob that has a bunch of types recorded, and then I
import define-generic which then gets a fresh and rebooted type record.

I can start by doing

(define old-frob frob)
(define-generic (frob x y) (old-frob x y))

And then go on to add in
(define-generic (frob (monster? x) (monster? y)) (monstrify x y))

That works, but, yes, it is not an elegant solution to this problem. A
sexp-based lisp1 with a robust and fast generics system would be an
awesome thing to behold♥