[racket-dev] P4P: A Syntax Proposal

From: Everett (webj2 at unoc.net)
Date: Thu Jul 29 20:46:14 EDT 2010

On Thu, 2010-07-29 at 15:37 -0400, Shriram Krishnamurthi wrote:
> Quick addendum:
> > Infix notation can be achieved unambiguously if you use LL(1) with
> > backtracking instead of just LL(1) by accepting expressions in the form
> > "(a b c)" that become "b(a, c)".   This is unambiguous only if you do not
> > allow including useless parenthesis around expressions
> This would not be a good idea.  Students are taught that infix goes
> hand-in-hand with useless parens -- "if in doubt, add parentheses, you
> can add as many as you want".  So giving them infix syntax but NOT
> permitting useless parens would fry their circuits.
> Shriram

I thought it was a clever idea because it forces parens around each
individual use, so the programmer has to think of associativity and
precedence, but allows a more readable representation.  So the d/dx
example becomes:

deffun: d/dx(f) =
  defvar: delta = 0.001
  fun: (x) in
    ((f((x + delta)) - f(x)) / delta)

Which can be understood easier than the prefix version but avoids all
the negatives of a complete infix notation.

The same could, of course, be accomplished with a macro (in a op b) ->
(op a b).  But in P4P that would end up looking like in(1, +, 2) which
isn't quite as nice.  Maybe yet another keyword for in:(1 + 2).
deffun: d/dx(f) =
  defvar: delta = 0.001
  fun: (x) in
    in:(in:( f( in:(x + delta) ) - f(x)) / delta) ; not as pretty...

Since your target use if for students, I could be convinced that infix
doesn't belong.  But both students and experienced (non-LISP)
programmers will complain about the prefix math. (And prefix comparison

BTW, any binary operation that expresses a relationship between first
and second operands could be clarified by writing it in infix.  So a
function application "match(string, pattern)" could be "(string match
pattern)".  So allowing infix does not destroy the understanding that +
is not any more special than any other function.

Also, if P4P is dependent on keywords like if: elif: etc. then macros
are crippled unless they can also make use of key words.  I believe Honu
somehow makes structural keywords unspecial, but requires redefining the
standard library (making the Honu language in addition to
H-Expressions).  An idea I had, but haven't worked the kinks out of yet,
was something like:
  if( cond ) then: {
  } else: {
  (if cond #:then expr-true #:else expr-false)
which also requires redefining the standard library.

Other examples:
  filter( lst ) with:(elem) { odd?(elem) } 
  (filer lst #:with (lambda (elem) (odd? elem)))
    case:("hello") { ... }
    else: { ... }
  (cases val #:case (lamda ("hello") ...) #:else ...)
which would require the macro look in the param list of the case's
lambda to find the pattern to match instead of in groupings of parens.

The switch example shows one more instance where someone will want to
define a structure that you haven't thought of.  I believe you said cond
will just have to be a bunch of if/elif.  But someone will still want to
implement cond.  If you can't handle creating new structures in your
syntax then P4P will only be useful to students.  It won't help pull
parenthesis-haters into the Racket camp (unless you implement all the
structures they could wish for in your parser, since
non-schemers/lispers aren't used to creating new syntaxes with macros).


Posted on the dev mailing list.