I'm somewhat reluctant to write this, as I am more conscious then ever of 
my limitations in terms of what time/energy I can commit and the 
consistency with which I can do so. But insofar as Honu was mentioned, I 
feel a bit obligated to at least chime in with some of my knowledge and 
observations of it, and some related possible strategies.

At the moment, aside from Matt and Jon, I think I have the most direct 
experience of Honu's inner workings. I've also spent a good number of years 
trying to toy with what I feel is a simpler and more modular approach, but 
I've often gotten caught up in bike shedding about names, interfaces and 
what to expose where. For various reasons, this is a domain which 
unfortunately makes it *very* easy to do so. My efforts so far can be found 
here: https://pkgs.racket-lang.org/package/infix-syntax, it is 
unfortunately under documented though. That being said, I would really 
recommend reading the source if possible, as it manages to do a lot in a 
really astoundingly little amount of code (the core logic that drives 
everything is a 7-line function). Specifically this 
https://github.com/mromyers/infix-syntax/tree/master/infix-syntax/private/core 
.
</self promotion>

Anyhow, regardless of the exact approach chosen, there are a couple of 
issues I forsee with trying to integrate honu-like features into racket-X. 
These aren't meant to be objections, just things that need to be worked on.

The most trivial one is that define-primitive-splicing-syntax-class 
<https://docs.racket-lang.org/syntax/Experimental.html#%28form._%28%28lib._syntax%2Fparse%2Fexperimental%2Fsplicing..rkt%29._define-primitive-splicing-syntax-class%29%29>
 
really should graduate out of experimental, since Honu depends really 
crucially on it for its nice integration with syntax-parse. While this 
function hasn't changed in years, the fact that it's in experimental does 
speak to some uncertainty about the interface it provides, which should be 
addressed one way or another. I do dislike the interface slightly, as 
requiring the number of items consumed is slightly awkward in Honu's case, 
introducing a slight inefficiency in redundantly needing to traverse the 
same input list a couple of times, but that's a minor annoyance at worst.

A more general problem is one of style. In racket currently, it seems to be 
encouraged to define keywords in a macro (using ~literal instead of 
~datum), as in 'else' for cond. This has the nice result of allowing you to 
rename keywords. Unfortunately, this introduces a couple headaches in 
something like Honu, which ends up making some things less flexible.

As an example, suppose you have the C ternary operator 'x ? y : z' . If you 
define : as a keyword, either everyone else that uses : as a keyword, like 
a list comprehension macro, will need to use the same one, or you can't use 
both simultaneously. In the best case scenario, : is defined either in 
core, or in a very central library, so most macros that use : as a keyword 
will use the same one. However, if someone later wants to define a : 
operator in a non-core library, using it will break every macro that uses : 
, since it's not the ~literal they're looking for.

The same problem exists for normal macros of course, but in practice it's 
not as much of a problem, because for one there just aren't that many of 
them, since #:keywords fill most of their role. No one seems to grumble for 
instance about the fact that their lovely 'else' function silently breaks 
all of their cond expressions. For operators however, you're usually 
drawing from a much smaller set, and so collisions are a bit more painful. 
Naturally, the solution is to just match : as a datum when it's used as a 
keyword, though this does prevent renaming the keyword if someone should 
wish. Still, I think as a matter of style and convention it's worth 
thinking about good rules of thumb and best practices for deciding when to 
define a keyword literal, and when to just use a datum.

This also ties into one of the other major sore points surrounding scope 
and collision. In languages like haskell and sml, one can 'upgrade' an 
already defined function to an operator with infixr / infixl statements. 
These are fairly convenient to work with, but it's hard to get something 
similar working in Racket, and would require greatly complicating how 
parsing works. The status quo is, if you want to define a new + function, 
one needs to do something like either:
(require (rename-in racket/base [+ add]))
(define-id-operator + add #:left- assoc #:prec 3)

or define the operator as add and use rename-out.

Now, you might not see this as too much of a hassle, but it does add a bit 
of mental overhead and room for user error compared to just, say, 
(declare-infixl + #:left-assoc #:prec 3)
The most natural way to implement something like the latter would be 
something like chez scheme's define-property, so this would be very nice to 
have if at all possible. It does require some thinking about its proper 
set-of-scopes semantics though.

Anyways, there are a few other thoughts I have on the subject, but this is 
getting long enough as it is, so I'll cut things short, and maybe provide 
some more later. First, two replies to some earlier comments.

Neil Van Dyke: For prior work, you should also look at Pratt's Top Down 
Operator Precedence Parsing paper, and the resulting CGOL language. Also, 
Disney's Sweet.js 

Alexis: Actually, there is a dsl for defining honu macros. See for example 
https://github.com/racket/honu/blob/master/honu/private/common.honu

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/racket-users/3fd57c4b-a8aa-43c5-879c-0211dc89bfbd%40googlegroups.com.

Reply via email to