[racket-dev] alt-exp syntax
A while ago I thought up an alternate syntax that converts directly into
S-Exp in an effort to reduce the number of parenthesis, hopefully
simplify the way a program looked, and still be completely compatible
(including macros) with the current Racket API. To test out my solution
I've been using it to implement my projects for CS 450 "Digital Signal
and Image Processing". This involves reading and writing image files
(in PPM or PGM format), using structs for internal representations,
doing numerical computations, and writing GUI code.
Overall Conclusion:
It does reduce parenthesis, but it isn't necessarily easier to
understand because you still need markers for all the groupings of
parentheses. It inter-operates with all Racket features, including
macros, and I think it makes _some_ code look a little cleaner. But it
isn't so fantastic that I would advocate it.
Detailed Explanation:
The syntax allows a great deal of freedom in style -- whether the user
chooses to use a function call notation or a colon, for example -- which
means 1: sometimes parenthesis are removed and sometimes they aren't,
and 2: the user could be inconsistent.
Example:
if( (|a < b|) ):
doX()
doY()
if: and: (|a < b|)
(|a > 0|)
doX()
doY()
It looks cleaner to use "and:" rather than "and(...)", but that means
the "if" looks stupid with the control-structure syntax "if( e ... ): e
..." so it just uses the colon syntax instead. I also tend to use "if"
with the function application form when it is conceptually inline in an
expression. (Where an "arithmetic if", or "ternary operator" would be
used in other languages.) This matches conceptually with other
languages, even though it is exactly the same "if" construct used in a
more control-flow-styled syntax. This does, however, emphasize that it
is very easy to be inconsistent in how syntax is used for the same
operation.
Here's another example, which shows OO code looking reasonably well, but
also the fact that I treat "new" as a function call conceptually so I
have parenthesis around some of the expression mixed with expressions
that use colon:
define: load-img(path)
set!(src-img read-pxm(path))
set!(out-img #f)
set!(src-bmp #f)
set!(out-bmp #f)
set!(src-hist send(plot-histogram(src-img 500 250) get-bitmap))
set!(out-hist #f)
send(frame modified #f)
send(src-canvas refresh)
send(out-canvas refresh)
send(src-hist-canvas refresh)
send(out-hist-canvas refresh)
new(button% [parent btn-pane]
[label "Load"]
[callback
lambda: [button event]
define: path get-file("Please select a file to load"
frame directory-part(last-in-path) #f #f null load-filters)
when( path ):
begin:
set!(last-in-path path)
load-img(path)
])
I think putting the "send" outside the parens lets me focus on the
object and method being called, so I worry less about the magic word
"send" in there. I also considered parsing out a "." in an id and
converting it to a send call, but I'm not annoyed enough at this current
notation to bother yet.
This colon syntax looks great for things like "begin", and reasonably
well for define. It is easy to follow these blocks with the eye and no
closing parenthesis is needed. The control-structure syntax is nice for
defining structs too, like:
define-struct(image):
[color? width height maxval rs gs bs]
define-struct(kernel):
:width ;dim of kernel
height ;dim of kernel
weights ;vector in ...
offset ;value added ...
scale ;after summing ...
Since I did not anticipate this case it shows that making a general-case
alternate syntax can be used in many features, which may even be added
to the language later via macros. This is an improvement over the
approach of hard-coding certain control structures into the syntax.
It still has oddities that must be remembered, like the use of the let
and for constructs:
let: :[a 1]
[b 2]
doX(a b)
for: :[a in-range(10)]
display(a)
In these examples, it isn't intuitive to have the colon after the let or
for and then the colon in front of the variable pairings. I find myself
thinking about what the s-exp form is and doing the conversion in my
head. I suppose if I learned alt-exp better I would just remember these
patterns, but they are no more intuitive than the current s-exp forms.
I never once used the "_(f a b)" form, since the "f(a b)" form is just
fine and for anything that needed to be grouped I would just use the "[e
e]" form. This left me with just one form of braces, though, so any
data structure that needs to be highly nested might not look as good.
E.g. the list of file dialog filters (which is a quoted list of lists,
so not too deep):
define: load-filters
'[["Any" "*.*"]
["PPM" "*.ppm"]
["PGM" "*.pgm"]]
Though that could be written as:
define: load-filters
':["Any" "*.*"]
["PPM" "*.ppm"]
["PGM" "*.pgm"]
Is that any clearer?
I find that the infix form is useful for functions that are not
commutative, like - / < and >. But for everything else I tend to use the
prefix form. I do, however, like the way function application looks.
Thanks,
-Everett Morse
p.s. Implementation of alt-exp available at
http://www.neptic.com/np/software/alt-exp.php
> -----Original Message-----
> From: dev-bounces at racket-lang.org
> [mailto:dev-bounces at racket-lang.org] On Behalf Of Everett
> Sent: 26 August 2010 20:10
> To: plt-dev Developers
> Subject: [racket-dev] alt-exp syntax
>
> I don't know if anyone cares about this, but I made a reader
> and #lang language for the alternate syntax I came up with
> (direct, obvious conversion to s-exp but allows writing fewer
> parens). Implementations are usually better appreciated than
> mere proposals. You can get at it
> here: http://www.neptic.com/np/software/alt-exp.php
>
> I noticed that one can provide a syntax colorer (the default
> is fine for my #lang language), but is there a way to provide
> an indenter since the default handling makes editing my
> alt-exp syntax slightly annoying in DrRacket.
>
>
> Thanks,
> -Everett
>
> _________________________________________________
> For list-related administrative tasks:
> http://lists.racket-lang.org/listinfo/dev