Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

"Readable" library for Common Lisp now available!

300 views
Skip to first unread message

dr.david....@gmail.com

unread,
May 9, 2013, 8:37:10 PM5/9/13
to
FYI:

I've just released a Common Lisp library called "readable".
It adds a new abbreviations to the Common Lisp reader for data and programs
(by modifying the readtable).

It provides 3 notational tiers, which are cumulative. Here's a summary:
1. Curly-infix-expressions (c-expressions): Add a Lispy infix notation, so
{a op b op c ...} => (op a b c...). No precedence, by intent.
2. Neoteric-expressions (n-expressions): An e(...) maps to (e ...),
and e{...} maps to e({...}).
3. Sweet-expressions (t-expressions): Parentheses are
deduced from indentation.

Unlike practically all past efforts to improve Lisp readability
(such as M-expressions), these notations are general, homoiconic,
and backwards-compatible with well-formatted s-expressions.
Macros, quasiquoting, special forms, and so on work just fine.
You can mix them with traditional s-expression notation, too.

Here's a trivial example of a sweet-expression:
defun fibfast (n)
if {n < 2} ; Indentation, infix {...}
n ; Single expr = no new list
fibup n 2 1 0 ; Simple calls

Which maps to this (the reader would accept either):
(defun fibfast (n)
(if (< n 2)
n
(fibup n 2 1 0)))

You can get the Common Lisp tutorial (which includes install instructions),
download the code (open source software using the MIT license),
and get other information from:
http://readable.sourceforge.net

If you're a Scheme user, the first two tiers are defined in SRFI-105;
the third tier (sweet-expressions) are defined in draft SRFI-110.

If you think s-expression notation came from the gods, well, this library
isn't for you. If you have an open mind, check it out. You might also view:
https://sourceforge.net/p/readable/wiki/Retort/

Constructive comments welcome.


--- David A. Wheeler



P.S. Installing and enabling it looks like this, per the tutorial:
./configure --prefix
make
make install
run_your_common_lisp_implementation
(require 'asdf)
(asdf:load-system :readable)
(readable:enable-sweet) ; Or whatever tier you want


Pascal J. Bourguignon

unread,
May 9, 2013, 9:40:44 PM5/9/13
to
"dwhe...@dwheeler.com" <dr.david....@gmail.com> writes:

> If you think s-expression notation came from the gods, well, this library
> isn't for you. If you have an open mind, check it out.

Seems to me you have to have more an open mind to think anything comes
from the gods than not…


--
__Pascal Bourguignon__ http://www.informatimago.com/
A bad day in () is better than a good day in {}.
You can take the lisper out of the lisp job, but you can't take the lisp out
of the lisper (; -- antifuchs

Antsan

unread,
May 10, 2013, 8:25:48 AM5/10/13
to
Not to say your library is useless or bad or will be the death of Lisp or anything like that. I just want to say that I don't consider Lisp syntax hard to read or ever did so. So, your commentary on that FAQ seems to be a bit strange to me.
Of course you are right when you say that others seem to have a problem with it.

Bigos

unread,
May 10, 2013, 11:03:07 AM5/10/13
to
On 10/05/13 01:37, dwhe...@dwheeler.com wrote:
> Constructive comments welcome.

After trying Paredit I love current bracket notation. I wonder if
someone would write something similar for your project and how useful it
would be.

Do you have in plans any tools that will make moving code around and
refactoring easier?

Max Rottenkolber

unread,
May 10, 2013, 6:00:12 PM5/10/13
to
> Here's a trivial example of a sweet-expression:
> defun fibfast (n)
> if {n < 2} ; Indentation, infix {...}
> n ; Single expr = no new list fibup n 2 1 0 ; Simple
> calls
>
> Which maps to this (the reader would accept either):
> (defun fibfast (n)
> (if (< n 2)
> n
> (fibup n 2 1 0)))

Why does 'calls' expand to '(fibup n 2 1 0)' and whats fibup?

Otherwise I think this neat. Especially the backwards compat is
convincing. I might try to write a program using Readable some
time. Worst case scenario is just running the code file through your
expander so nothing can go wrong aye?

Cheers,
max

Antsan

unread,
May 10, 2013, 6:20:32 PM5/10/13
to
What you have there is badly mangled.

The line in question was
fibup n 2 1 0

Followed by the comment
; Simple calls

Pascal J. Bourguignon

unread,
May 10, 2013, 7:34:49 PM5/10/13
to
You see, that's why it's not a good idea. At least with parentheses
(and without using ; comments), the code can be "mangled" as you want,
the parentheses still indicate the structure.

David A. Wheeler

unread,
May 10, 2013, 9:33:51 PM5/10/13
to
Bigos:
> After trying Paredit I love current bracket notation. I wonder if
> someone would write something similar for your project and how useful it
> would be.
> Do you have in plans any tools that will make moving code around and
> refactoring easier?

We *want* to create such tools, but our focus so far has been on getting a good notation. So the answer is "not yet, but we already know of the need." Some of the reformatting work for Lisps become completely unnecessary, too. In particular, there's no need to keep indent and parens in sync, because the indents automatically generate the parens.

I've briefly looked into doing some basics for vim (looks straightforward), and I can't imagine that there'd be a problem doing this in the emacsen. There are other tools (like Eclipse) that people use too.

We do have a pretty-printer called "sweeten" that reads traditional s-expressions and generates sweet-expressions. Sweeten is, itself, written using sweet-expressions. That's not *exactly* what you asked for, but it's a step that way.

If you'd like to help that'd be awesome!


Informatimgo:
> You see, that's why it's not a good idea. At least with parentheses
> (and without using ; comments), the code can be "mangled" as you want,
> the parentheses still indicate the structure.

Never using ;-comments brings its own problems. Over-commenting is bad,
but NEVER commenting is a problem too. We *definitely* support ;-comments.

In any case, we had this problem too, and we solved it in a surprising way:
the "!" (along with space and tab) is an indent character. This turns out
to work surprisingly well, and eliminates the usual problems with indentation-
based syntaxes (e.g., lots of transports munge leading whitespace).
It also makes it possible to visually group certain indents, which is handy.
(It does mean that you have to escape symbols with a leading "!" if they
begin a line, but that doesn't seem to be a serious problem.)

Here's the fibfast example, using "!" indents:

defun fibfast (n)
! if {n < 2} ; Indentation, infix {...}
! ! n ; Single expr = no new list fibup n 2 1 0 ; Simple
! ! fibup n 2 1 0 ; Simple function calls


Presumably many of the people in this mailing list don't find Lisp syntax impossible to read, or you wouldn't be on this list :-). But a *lot* of people don't like Lisp's traditional syntax. And even those who are fine with traditional notation might enjoy using an updated notation with new capabilities. My hope is that this notation (and its implementing library) would be a useful tool for those people.

avodo...@gmail.com

unread,
May 10, 2013, 9:43:03 PM5/10/13
to
This is interesting.
Do you have printer for sweet-expressions? It would be interesting to convert some of the exising big programs, like hunchentoot, into sweet-expressions. I.e. read s-expr by s-expr the sources and print as sweet-expressions.

David A. Wheeler

unread,
May 10, 2013, 10:35:51 PM5/10/13
to
On Friday, May 10, 2013 9:43:03 PM UTC-4, avodo...@gmail.com wrote:
> This is interesting.
> Do you have printer for sweet-expressions? It would be interesting to convert some of the exising big programs, like hunchentoot, into sweet-expressions. I.e. read s-expr by s-expr the sources and print as sweet-expressions.

The "sweeten" program accepts s-expressions and generates sweet-expressions. Be sure to give it the "-C" option (for "Common Lisp"; by default it expects to read Scheme). It's fundamentally a pretty-printer.

--- David A. Wheeler

David A. Wheeler

unread,
May 10, 2013, 11:03:58 PM5/10/13
to
On Friday, May 10, 2013 9:43:03 PM UTC-4, avodo...@gmail.com wrote:
> Do you have printer for sweet-expressions? It would be interesting to convert some of the exising big programs, like hunchentoot, into sweet-expressions. I.e. read s-expr by s-expr the sources and print as sweet-expressions.

That's a great idea, so I tried out "sweeten" on hunchentoot (BSD license). The "sweeten" program is currently more focused on Scheme, so sweeten can't yet handle some of the hunchentoot files. I think that'd be easy to fix. That said, here is hunchentoot's "make-docstrings" in sweet-expressions; I ran it through "sweeten" and then did some mild hand-improvements to make it "pretty". I put "!" as the first indent character, in the hopes that more readers will be able to see the indentation.

--- David A. Wheeler


=======================================================

;; -*- Lisp -*-

defpackage :make-docstrings :use(:cl) :export(#:parse-doc)

in-package :make-docstrings

defclass formatting-stream
! trivial-gray-streams:fundamental-character-input-stream()
! understream(:initarg :understream :reader understream)
! width :initarg :width :initform
! error "missing :width argument to formatting-stream creation"
! :reader
! width
! column :initform 0 :accessor column
! word-wrap-p :initform t :accessor word-wrap-p
! word-buffer :initform
! make-array 1000 :element-type 'character :adjustable t :fill-pointer 0
! :reader
! word-buffer

defun write-char% (char stream)
! incf column(stream)
! write-char char understream(stream)

defun print-newline (stream)
! write-char #\newline understream(stream)
! setf column(stream) 0

defun buffer-not-empty-p (stream)
! plusp length(word-buffer(stream))

defun maybe-flush-word (stream)
! when buffer-not-empty-p(stream)
! cond
! {width(stream) < {column(stream) + length(word-buffer(stream))}}
! print-newline stream
! plusp(column(stream)) write-char%(#\space stream)
! loop for char across word-buffer stream do
! write-char% char stream
! setf fill-pointer(word-buffer(stream)) 0

defmethod trivial-gray-streams:stream-write-char
! stream(formatting-stream) char
! if word-wrap-p(stream)
! cond
! eql(#\space char) maybe-flush-word(stream)
! eql(#\newline char)
! maybe-flush-word stream
! print-newline stream
! t vector-push-extend(char word-buffer(stream))
! write-char char understream(stream)

defmethod trivial-gray-streams:stream-line-column
! stream()
! {column(stream) + length(word-buffer(stream))}

defmethod trivial-gray-streams:stream-write-string
! stream(formatting-stream) string &optional start end
! loop for i from {start or 0} below {end or length(string)} do
! write-char char(string i) stream

defmethod trivial-gray-streams:stream-terpri
! (stream(formatting-stream))
! write-char #\newline stream

defmethod close
! stream(formatting-stream) &key abort
! unless abort maybe-flush-word(stream)

defmethod setf
! word-wrap-p
! :before
! new-value stream(formatting-stream)
! maybe-flush-word stream
! when buffer-not-empty-p(stream)
! print-newline(stream)

defun test-wrap-stream (text)
! with-output-to-string
! s()
! with-open-stream
! s $ make-instance 'formatting-stream :understream s :width 20
! write-string text s
! setf word-wrap-p(s) nil
! format s "~&OFF~%"
! write-string text s
! format s "~&ON~%"
! setf word-wrap-p(s) t
! write-string text s

defmacro replace-regexp
! place regex replacement
! . `
! setf
! ,place
! cl-ppcre:regex-replace-all ,regex ,place ,replacement

defun collapse-whitespace (string)
! replace-regexp
! string
! "[ \\t]*\\n[ \\t]*"
! #.make-string(1 :initial-element #\newline)
! replace-regexp string "(?<!\\n)\\n" " "
! remove #\newline string

defvar *output*

defun xml-to-docstring% (node transform)
! stp:do-children
! child node
! typecase child
! stp:text
! write-string funcall(transform stp:data(child)) *output*
! stp:element
! ecase
! intern string-upcase(stp:local-name(child)) :keyword
! :p
! terpri *output*
! terpri *output*
! xml-to-docstring% child transform
! :a(:code :tt :blockquote :span :ul)
! xml-to-docstring% child transform
! :li() xml-to-docstring%(child transform) terpri(*output*)
! :ref(:arg :em :i)
! xml-to-docstring%
! child
! alexandria:compose #'string-upcase transform
! (:sup())
! :pre
! terpri *output*
! terpri *output*
! setf word-wrap-p(*output*) nil
! xml-to-docstring% child #'identity
! setf word-wrap-p(*output*) t
! terpri *output*

defun xml-to-docstring (description-node)
! with-output-to-string
! s()
! with-open-stream
! *output*
! make-instance 'formatting-stream :understream s :width 75
! xml-to-docstring% description-node #'collapse-whitespace

defun maybe-qualify-name (name package-name)
! if find(#\: name)
! name
! format nil "~A:~A" package-name name

defun get-doc-entry-type (node)
! let <* basic-type $ intern string-upcase(stp:local-name(node)) :keyword *>
! if eq(basic-type :function)
! if stp:attribute-value(node "generic")
! :generic-function
! :function
! basic-type

defun skip-to (stream char)
! loop until eql(char peek-char(nil stream)) do
! read-char stream

defun get-simple-def-docstring (source-string position)
! with-input-from-string
! s source-string :start 1+(position)
! read s
! read s
! read s
! skip-to s #\"
! list :start file-position(s) :text read(s) :end file-position(s)

defun get-complex-def-docstring (source-string position)
! with-input-from-string
! s source-string :start 1+(position)
! read s
! read s
! read s
! loop
! let* <* start-of-clause $ file-position s \\ clause $ read s *>
! when eql(first(clause) :documentation)
! ! file-position s start-of-clause
! ! skip-to s #\(
! ! read-char s
! ! read s
! ! skip-to s #\"
! ! return
! ! list
! ! :start
! ! file-position s
! ! :text
! ! read s
! ! :end
! ! file-position s

defun get-doc-function (type)
! case type
! :function(:special-variable) 'get-simple-def-docstring
! :generic-function(:class) 'get-complex-def-docstring

defun source-location-flatten (location-info)
! apply
! #'append
! rest find(:location rest(location-info) :key #'first)

defvar *files*

defclass file ()
! file-pathname(:initarg :file-pathname :reader file-pathname)
! docstrings :initform nil :accessor docstrings
! contents :accessor contents

defmethod initialize-instance
! :after
! file(file) &key file-pathname
! setf
! slot-value file 'contents
! alexandria:read-file-into-string file-pathname

defun get-file (pathname)
! or
! gethash pathname *files*
! setf
! gethash pathname *files*
! make-instance 'file :file-pathname pathname

defun record-docstring (doc-docstring get-doc-function symbol-name)
! let
! \\
! definitions
! remove-if
! lambda definition()
! ! or
! ! cl-ppcre:scan "(?i)^\\s*\\(defmethod\\s" first(definition)
! ! eql first(second(definition)) :error
! swank:find-definitions-for-emacs symbol-name
! case length(definitions)
! 0 warn("no source location for ~A" symbol-name)
! 1
! let*
! \\
! source-location $ source-location-flatten first(definitions)
! file $ get-file getf(source-location :file)
! push
! list*
! :doc-docstring
! doc-docstring
! funcall
! get-doc-function
! contents file
! getf source-location :position
! docstrings file
! 2 warn("multiple source locations for ~A" symbol-name)

defun parse-doc (pathname default-package-name)
! let <* *files* $ make-hash-table :test #'equal *>
! xpath:with-namespaces
! (("clix" "http://bknr.net/clixdoc"))
! xpath:do-node-set
! node
! xpath:evaluate
! "//*[clix:description!='']"
! cxml:parse pathname stp:make-builder()
! let
! \\
! type $ get-doc-entry-type node
! symbol-name
! maybe-qualify-name
! stp:attribute-value node "name"
! default-package-name
! xpath:do-node-set
! description xpath:evaluate("clix:description" node)
! alexandria:when-let
! get-doc-function get-doc-function(type)
! record-docstring
! xml-to-docstring description
! get-doc-function
! symbol-name
! *files*

Max Rottenkolber

unread,
May 11, 2013, 8:49:46 AM5/11/13
to
> defun fibfast (n)
> ! if {n < 2} ; Indentation, infix {...}
> ! ! n ; Single expr = no new list fibup n 2 1 0 ; Simple
> ! ! fibup n 2 1 0 ; Simple function calls

Now THAT is horrible. This essentially 10, 20, 40, FORTRAN code.

Compare this to (defun fibtest (n) (if (< n 2) n (fibup n 2 1 0))) which
uses nesting instead of counting the level.

'(fibup n 2 1 0)' is a standalone form, while '! ! fibup n 2 1 0' is
not. You are introducing completely useless state.

I can only give one advice: Sweet expressions should strictly matter
on the presentation layer ONLY. The s-expression encoding is in its way
a perfect compromise between computer and human readability. If you want
to seriously employ sweet-exprs, consider implementing them as an editor
layer. So you can read and write sweet-exprs while editing code, but the
source on disk should always be classic s-exprs because there will always
be parties (e.g. the compiler) who don't care about the syntax sugaring.

cheers,
max

Max Rottenkolber

unread,
May 11, 2013, 8:52:17 AM5/11/13
to
Sadly the exclamation marks plus my newsreaders mangling make this
completely undigestible for me. This is a classic job for
paste.lisp.org.

Bigos

unread,
May 11, 2013, 9:10:35 AM5/11/13
to
On 11/05/13 13:49, Max Rottenkolber wrote:

> a perfect compromise between computer and human readability. If you want
> to seriously employ sweet-exprs, consider implementing them as an editor
> layer. So you can read and write sweet-exprs while editing code, but the
> source on disk should always be classic s-exprs because there will always
> be parties (e.g. the compiler) who don't care about the syntax sugaring.
>
> cheers,
> max
>

How many people will want an Emacs mode for that?

Paul Rubin

unread,
May 11, 2013, 9:13:16 AM5/11/13
to
"David A. Wheeler" <dwhe...@dwheeler.com> writes:
> We *want* to create such tools, but our focus so far has been on
> getting a good notation. So the answer is "not yet, but we already
> know of the need."

I'm not reacting to this as badly as some of the die-hards but it seems
to me, that after the twiddling of the surface syntax, you've still got
Lisp at the other end. If you're trying to modernize Lisp, there are
deeper issues to address.

You're probably already familiar with:

http://www.cs.kent.ac.uk/people/staff/dat/miranda/wadler87.pdf

which is one example of a deeper revamp (it's about a predecessor of
Haskell). But, once you've done something like that, it's not Lisp any
more. Lots of people have moved to such alternatives by now, but those
who continue to use CL seem to do so because they like it the way it is,
including the parentheses.

Either way though, I'd be interested to know if your syntax works with
Clojure.

Max Rottenkolber

unread,
May 11, 2013, 10:40:53 AM5/11/13
to
> How many people will want an Emacs mode for that?

I would at least try it out. I am personally quite familiar with the
s-expression syntax, but maybe some things like declarative parsers could
be rendered in a real pretty way using sweet expressions.

Antsan

unread,
May 11, 2013, 11:16:24 AM5/11/13
to
Actually, no. If line breaks are inserted into comments the resulting code still will become nonsense.

David A. Wheeler

unread,
May 11, 2013, 11:52:56 AM5/11/13
to
Hmm. Okay, try this:
http://paste.lisp.org/display/137111

--- David A. Wheeler

avodo...@gmail.com

unread,
May 11, 2013, 4:36:04 PM5/11/13
to
On Saturday, May 11, 2013 6:03:58 AM UTC+3, David A. Wheeler wrote:
> That's a great idea, so I tried out "sweeten" on hunchentoot (BSD license).
> [...]

You may want to publish the result side-by-side with the original hunchentoot code, like this: https://s3-eu-west-1.amazonaws.com/avpub/readable-demo.html
(I don't know what version of hunchentoot you use, so I've just included the last version from git).

Some notes. Lets consider the defclass formatting-stream. This forms defines a class formatting-stream inherited from trivial-gray-streams:fundamental-character-input-stream and having 5 slots: understream, width, column, word-wrap-p, word-buffer. The sweet-expression variant reflects this not very clearly.

I realize that "sweeten" is just a pretty printer. If we print the CL code with standard CL pretty-printer it would not reflect the code meaning cleary as well.

Can you demostrate better way of formatting the sweet-expression variant of defclass formatting-stream?

As for the Readable idea of keeping the Lisp code-as-data approach and just providing another external (textual) representation of the same data structure as the traditional s-expr formatted code, in my opinion various external representations of programming code have right to exist.

sweet-expressions resemble YAML.

I think in theory program code may have different external representations, not necessary textual, maybe also graphical, maybe in form of voice commands and so on. As long as our macros see it as the same data structure, it is OK.

David A. Wheeler

unread,
May 11, 2013, 8:29:59 PM5/11/13
to
On Saturday, May 11, 2013 4:36:04 PM UTC-4, avodo...@gmail.com wrote:
> You may want to publish the result side-by-side with the original hunchentoot code, like this: https://s3-eu-west-1.amazonaws.com/avpub/readable-demo.html

That looks nice!

> (I don't know what version of hunchentoot you use, so I've just included the last version from git).

I used the tarball from version 1.2.18. You can get the original code from:
http://paste.lisp.org/display/137116

> Some notes. Lets consider the defclass formatting-stream. This forms defines a class formatting-stream inherited from trivial-gray-streams:fundamental-character-input-stream and having 5 slots: understream, width, column, word-wrap-p, word-buffer. The sweet-expression variant reflects this not very clearly.


> Can you demostrate better way of formatting the sweet-expression variant of defclass formatting-stream?

Probably. I mostly just accepted what the "sweeten" pretty-printer did. I'll see what I can do.

--- David A. Wheeler

David A. Wheeler

unread,
May 12, 2013, 11:47:32 PM5/12/13
to
On Saturday, May 11, 2013 4:36:04 PM UTC-4, avodo...@gmail.com wrote:

> Can you demonstrate better way of formatting the sweet-expression variant of defclass formatting-stream?


Yes. Here's what I think is a much-improved example:
http://paste.lisp.org/display/137135


By default, expressions like:
! x y z
map to (x y z).

That's a reasonable default... but there are many Common Lisp constructs
which involve pairs of items that are *logically* related, but from a
*list* point of view are at the same level. E.G., ":reader word-buffer"
is a keyword followed by a value.
Some previous indent systems for Lisp, like SRFI-49, forced you to put
the whole list inside (...), or use lots of lines, to suppress this behavior.

In sweet-expressions, a "\\" can be used to improve things.
In the middle of a line, it lets you break up lines without having to *use*
many lines... so you can write ":accessor \\ word-wrap-p" instead of having
to use two lines for each one.

A "\\", if it begins a line (after the indent),
means "nothing at all". This makes it easy
to create "lists of lists" such as those that occur in a defclass.

--- David A. Wheeler

Dan Lentz

unread,
May 15, 2013, 3:58:43 PM5/15/13
to
I think this is an interesting example of reader customization, but other than that I do not understand why one would want to do this? It seems to strive for equivalence to sexpression (which a few posts have pointed out its shortcomings in this regard) But even if it were, do any of these syntaxes provide any addional expressiveness? Is this just intended as a novelty or am I missing some kind of thing that migh be more elegantly expressed with any of these alternative notations? No criticism intended I quite enjoy reader hacks, although I don't frequently use them at least at present.

Though, Wilbur's !-reader I think is the most useful one I've come across and is indispensable when working with namespaced URI's. I'm not sure I can think of any others in the same league... Can anyone come up with others?

Pascal J. Bourguignon

unread,
May 15, 2013, 6:37:21 PM5/15/13
to
Yes, it's a rite of passage, and we can agree that David passed with
flying colors. The next level is to write one's own CL implementation.

avodo...@gmail.com

unread,
May 15, 2013, 7:13:30 PM5/15/13
to
David A. Wheeler:
> On Saturday, May 11, 2013 4:36:04 PM UTC-4, avodo...@gmail.com wrote:
>
> > Can you demonstrate better way of formatting the sweet-expression variant of defclass formatting-stream?
>
> Yes. Here's what I think is a much-improved example:
>
> http://paste.lisp.org/display/137135

To be honest, I do not understand how to read it.

> In sweet-expressions, a "\\" can be used to improve things.
> In the middle of a line, it lets you break up lines without having to *use*
> many lines... so you can write ":accessor \\ word-wrap-p" instead of having
> to use two lines for each one.

Why would one want to split :accessor and word-wrap-p into two separate lines?

> A "\\", if it begins a line (after the indent),
> means "nothing at all". This makes it easy
> to create "lists of lists" such as those that occur in a defclass.

The "means "nothing at all" part is obscure to me. What exactly this nothing at all means and how it helps to build lists of lists.

Joost Kremers

unread,
May 16, 2013, 7:00:30 PM5/16/13
to
dwhe...@dwheeler.com wrote:
> FYI:
>
> I've just released a Common Lisp library called "readable".
> It adds a new abbreviations to the Common Lisp reader for data and programs
> (by modifying the readtable).
>
> It provides 3 notational tiers, which are cumulative. Here's a summary:
> 1. Curly-infix-expressions (c-expressions): Add a Lispy infix notation, so
> {a op b op c ...} => (op a b c...). No precedence, by intent.
> 2. Neoteric-expressions (n-expressions): An e(...) maps to (e ...),
> and e{...} maps to e({...}).
> 3. Sweet-expressions (t-expressions): Parentheses are
> deduced from indentation.

Though I'm just a hobbyist (Emacs) Lisp programmer, I hope I'm
nonetheless allowed some questions/comments. The idea itself seems
interesting, though I have to admit I personally *like* s-expressions.
They somehow help me structure my thoughts when writing code and they
don't bother me when reading it. In fact, I find some of the
t-expression examples on your website more difficult and confusing to
read than the original s-expressions...

But that's probably a matter of personal taste and of getting used to,
so there's little need to debate that. What I am wondering, however,
when reading the explanations and the examples, is what kind of
improvement you're aiming for. Or, put differently, what your target
group really is. Are you targeting this at lispers that have
considerable experience with s-expressions, to simplify their lives, so
to speak, or are you hoping it will also appeal to programmers that have
so far eschewed Lisp because of the parentheses?

The main problem I see with the latter group is that t-expressions seem
to require a good working knowledge of s-expression syntax in Lisp. I
get the feeling that many of the syntactic constructions that are used
in your n- and t-expressions would seem completely arbitrary and
pointless otherwise. For example, it is not clear to me what \\ actually
does and when and why it's needed. Now, I'm sure I can figure it out if
I wanted to, but if it's not immediately obvious to someone that's
accustomed to s-expressions, how are you gonna explain it to someone who
doesn't (want to) know them? I mean, you say that \\ is useful for
"creating lists of lists", but that means that the programmer still
needs to be fully aware of the list structure of the code s/he's
writing. That being the case, I'm inclined to think that it might be
better to just represent the list structure directly.

Other things also seem quite weird if you don't know the underlying list
structure. One of the examples contains the following line:

let loop (lst(lst) sum(0))

To a non-lisper, `lst(lst)` and `sum(0)` are going to look like function
applications, but that is patently *not* what they are. Though in other
contexts, the syntax `fn(arg)` *can* be function application.

More generally, if you don't know how n/t-expressions are going to be
translated into s-expressions, such details of the syntax make it
impossible to see at a glance how the code is structured, or, to borrow
some terminology from linguistics, what the heads are and what the
dependents. So that makes me wonder how learnable this syntax is for
lisp-newbies. And the same thing makes me wonder how appealing
n/t-expressions are for seasoned lispers. Their basic idea is very
simple and attractive, but there are quite a few details about their
syntax, which makes the actual implementation much more complicated.

Another question that I have is how you do backquote and unquote. You
say that macros are possible in t-expressions, but the only examples I
have found are Scheme macros (and I don't know Scheme). Perhaps I
haven't looked hard enough, though...

Lastly, your retort is quite flammable... Besides, I believe it's not
always factually correct. Especially in the first part, where you claim
that the fact that early lispers intended to implement m-expressions
proves that Lisp's syntax is ugly. IMO it doesn't prove that at all. It
could simply be the case (and this is what the FAQ implies, I think)
that early lispers found it weird, for the simple reason that it was so
different from what they knew. Not because it was "undesirable". The
FAQ's argument is that as time passed, they found that programming in
s-expressions is not only doable, but has clear advantages. You don't
really address that argument, though.

Anyway, that's just a few thoughts and comments. Feel free to reply or
ignore as you see fit. :-)


--
Joost Kremers joostk...@fastmail.fm
Selbst in die Unterwelt dringt durch Spalten Licht
EN:SiS(9)
0 new messages