[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.lisp

one word comment

Taoufik Dachraoui

8/7/2015 10:49:00 PM

Hi

It is nice to have a one word comment because
it adds some useful structure to the code and
it makes the code more readable

(set-macro-character #\(
#'(lambda (stream char)
(let ((r) (a (read-delimited-list #\) stream t)))
(labels ((foo (e)
(cond
((atom e) e)
((and (symbolp (car e))
(eq (char (symbol-name (car e)) 0) #\.))
(foo (cdr e)))
(t (cons (foo (car e)) (foo (cdr e)))))))
(foo a)))))


(match e
.when pattern .then form
.when pattern .then form
....)

or

(match e
pattern .-> form
pattern .-> form
....)

Is there any issue I did not see by defining the macro character #\( ?

-Taoufik
34 Answers

Kaz Kylheku

8/8/2015 1:41:00 AM

0

On 2015-08-07, Taoufik Dachraoui <dachraoui.taoufik@gmail.com> wrote:
> Is there any issue I did not see by defining the macro character #\( ?

Stuff I can think of off the top of my head:

The read-delimited-list function doesn't handle dotted lists like (1 2 . 3).

I.e. read-delimited-list isn't the function which implements the ( read
macro.

A possible approach, to avoid implementing a dotted list reader, might be to
capture that function using get-dispatch-macro-character, and then funcall it out
of your own lambda.

CLISP:

$ clisp -q
[1]> (get-macro-character #\()
#<SYSTEM-FUNCTION SYSTEM::LPAR-READER> ;
NIL
[2]> (funcall * *standard-input* #\()
2 3 4 5 . 6)
(2 3 4 5 . 6)
[3]>

I also wonder whether the list rewrite that you do in your local function foo
affects the ability to match forms to original file/line number information in
some Lisps.

Taoufik Dachraoui

8/8/2015 10:08:00 AM

0

But how i did it seems to work with dotted lists

The only thing is that I cannot have a one-word-comment after the dot:

? '(a .b . c .d)
Reader error on #<CCL::RECORDING-CHARACTER-INPUT-STREAM #xCF3C826>, near position 13:
Dot context error.
[Condition of type CCL::SIMPLE-READER-ERROR]

For example the following is working fine (recognise the float number) and the dot is handled correctly:
? '(progn .45 .comment . ((print .comment 'hello)))
(PROGN 0.45 (PRINT 'HELLO))

? '(a .x b . (c .x (d .x e . f) .x))
(A B C (D E . F))
? '(a b . (c (d e . f)))
(A B C (D E . F))

-Taoufik

Taoufik Dachraoui

8/8/2015 10:12:00 AM

0

But how i did it seems to work with dotted lists

The only thing is that I cannot have a one-word-comment after the dot:

? '(a .b . c .d)
Reader error on #<CCL::RECORDING-CHARACTER-INPUT-STREAM #xCF3C826>, near position 13:
Dot context error.
[Condition of type CCL::SIMPLE-READER-ERROR]

For example the following is working fine (recognise the float number) and the dot is handled correctly:
? '(progn .45 .comment . ((print .comment 'hello)))
(PROGN 0.45 (PRINT 'HELLO))

? '(a b .3 . (c .4 (d e .5 . f) .6))
(A B 0.3 C 0.4 (D E 0.5 . F) 0.6)
? '(a .x b .3 . (c .x .4 (d .x e .5 . f) .6 .x))
(A B 0.3 C 0.4 (D E 0.5 . F) 0.6)
?

? '(a .x b .3 . (c .x .4 (d .x e .5 . ((0.6 .x . 0.7))) .8 .x))
(A B 0.3 C 0.4 (D E 0.5 (0.6 . 0.7)) 0.8)

? '(a b .3 . (c .4 (d e .5 . ((0.6 . 0.7))) .8))
(A B 0.3 C 0.4 (D E 0.5 (0.6 . 0.7)) 0.8)

it seems working fine as far as I can see


-Taoufik

Taoufik Dachraoui

8/8/2015 10:17:00 AM

0

> Kaz wrote:
> The read-delimited-list function doesn't handle dotted lists like (1 2 . 3).

But the follwoing test shows that it does:

? '(a b .3 . (c .4 (d e .5 . ((0.6 . 0.7))) .8))
(A B 0.3 C 0.4 (D E 0.5 (0.6 . 0.7)) 0.8)

? '(a .x b .3 . (c .x .4 (d .x e .5 . ((0.6 .x . 0.7))) .8 .x))
(A B 0.3 C 0.4 (D E 0.5 (0.6 . 0.7)) 0.8)

-Taoufik

Pascal J. Bourguignon

8/8/2015 11:11:00 AM

0

Taoufik Dachraoui <dachraoui.taoufik@gmail.com> writes:

> But how i did it seems to work with dotted lists

Because you are using an implementation that doesn't have a conforming
read-delimited-list function.

$ clall -r '(ignore-errors (with-input-from-string (in "a . b)") (read-delimited-list #\) in)))'

Armed Bear Common Lisp --> NIL, #<READER-ERROR {287C20AB}>
Clozure Common Lisp --> (A . B)
CLISP --> NIL, #<SYSTEM::SIMPLE-READER-ERROR #x000334C26C30>
CMU Common Lisp --> NIL, #<READER-ERROR {581A622D}>
ECL --> NIL, #<a SI::SIMPLE-READER-ERROR>
SBCL --> NIL, #<SB-INT:SIMPLE-READER-ERROR "dot context error" {1003A22A93}>


read-delimited-list is specified in no uncertain terms:


read-delimited-list looks ahead at each step for the next
non-whitespace[2] character and peeks at it as if with peek-char. If
it is char, then the character is consumed and the list of objects
is returned. If it is a constituent or escape character, then read
is used to read an object, which is added to the end of the list. If
it is a macro character, its reader macro function is called; if the
function returns a value, that value is added to the list. The
peek-ahead process is then repeated.


Therefore here is a conforming implementation of read-delimited-list, on
the standard character set (for a "correct" extension to unicode, one
would need to include a table of all the unicode whitespace characters).

Notice that we don't enter into the detail of constituent and escape, we
assume that any non-whitespace and non macro-character is a
consitituent or an escape character.

Notice also that there's is simply no way to determine the syntax type
of a character! It's possible to change the syntax type of characters
using SET-SYNTAX-FROM-CHAR, so the current readtable could contain only
whitespaces or only escape characters, or it could exchange the role of
whitespaces and constituent characters, which makes it impossible in
general to even probe it. Therefore we just assume here that the set of
whitespace is the standard specified default set.

A real implementation would have access to the current syntax type of
the characters.



(shadow 'read-delimited-list)

(defun whitespacep (ch)
(find ch #(#\space #\tab #\newline #\linefeed #\page #\return)))

(defun constituent-or-escape-p (ch)
(and (not (get-macro-character ch))
;; order important.
(not (whitespacep ch)))

(defun read-delimited-list (ch &optional (stream *standard-input*)
recursivep)
(let ((result '()))
(loop
(let ((next (peek-char nil stream)))
(cond ((char= next ch)
(return (nreverse result)))
((let ((mc (get-macro-character next)))
(when mc
(let ((objects (multiple-value-list (funcall mc stream (read-char stream)))))
(when objects
(push (first objects) result)))
t)))
((constituent-or-escape-p next)
(push (read stream t nil recursivep) result))
(t ; whitespace
(read-char stream)))))))

(with-input-from-string (in "a b d)")
(read-delimited-list #\) in))
(a b d)

(with-input-from-string (in "a '(a b c) #(1 2 3) b d)")
(read-delimited-list #\) in))
(a '(a b c) #(1 2 3) b d)

(princ (nth-value 1 (ignore-errors
(with-input-from-string (in "a b . d)")
(read-delimited-list #\) in)))))
Reader error on #<string-input-stream :closed #x30200232C20D>:
Dot context error in ".".#<ccl::simple-reader-error #x302002328C4D>



--
__Pascal Bourguignon__ http://www.informat...
â??The factory of the future will have only two employees, a man and a
dog. The man will be there to feed the dog. The dog will be there to
keep the man from touching the equipment.� -- Carl Bass CEO Autodesk

Pascal J. Bourguignon

8/8/2015 11:13:00 AM

0

Taoufik Dachraoui <dachraoui.taoufik@gmail.com> writes:

>> Kaz wrote:
>> The read-delimited-list function doesn't handle dotted lists like (1 2 . 3).
>
> But the follwoing test shows that it does:

That's why you should be wary of tests in programmings. Tests don't
prove your program is correct. They can only prove it's incorrect.

Here, your test failed to prove your program is not conforming, but it
still is not conforming.


--
__Pascal Bourguignon__ http://www.informat...
â??The factory of the future will have only two employees, a man and a
dog. The man will be there to feed the dog. The dog will be there to
keep the man from touching the equipment.� -- Carl Bass CEO Autodesk

Pascal J. Bourguignon

8/8/2015 11:16:00 AM

0

"Pascal J. Bourguignon" <pjb@informatimago.com> writes:

> Taoufik Dachraoui <dachraoui.taoufik@gmail.com> writes:
>
>> But how i did it seems to work with dotted lists
>
> Because you are using an implementation that doesn't have a conforming
> read-delimited-list function.
>
> $ clall -r '(ignore-errors (with-input-from-string (in "a . b)") (read-delimited-list #\) in)))'
>
> Armed Bear Common Lisp --> NIL, #<READER-ERROR {287C20AB}>
> Clozure Common Lisp --> (A . B)
> CLISP --> NIL, #<SYSTEM::SIMPLE-READER-ERROR #x000334C26C30>
> CMU Common Lisp --> NIL, #<READER-ERROR {581A622D}>
> ECL --> NIL, #<a SI::SIMPLE-READER-ERROR>
> SBCL --> NIL, #<SB-INT:SIMPLE-READER-ERROR "dot context error" {1003A22A93}>
>
>
> read-delimited-list is specified in no uncertain terms:
>
>
> read-delimited-list looks ahead at each step for the next
> non-whitespace[2] character and peeks at it as if with peek-char. If
> it is char, then the character is consumed and the list of objects
> is returned. If it is a constituent or escape character, then read
> is used to read an object, which is added to the end of the list. If
> it is a macro character, its reader macro function is called; if the
> function returns a value, that value is added to the list. The
> peek-ahead process is then repeated.
>
>
> Therefore here is a conforming implementation of read-delimited-list, on
> the standard character set (for a "correct" extension to unicode, one
> would need to include a table of all the unicode whitespace characters).
>
> Notice that we don't enter into the detail of constituent and escape, we
> assume that any non-whitespace and non macro-character is a
> consitituent or an escape character.
>
> Notice also that there's is simply no way to determine the syntax type
> of a character! It's possible to change the syntax type of characters
> using SET-SYNTAX-FROM-CHAR, so the current readtable could contain only
> whitespaces or only escape characters, or it could exchange the role of
> whitespaces and constituent characters, which makes it impossible in
> general to even probe it. Therefore we just assume here that the set of
> whitespace is the standard specified default set.
>
> A real implementation would have access to the current syntax type of
> the characters.
>
>
>
> (shadow 'read-delimited-list)
>
> (defun whitespacep (ch)
> (find ch #(#\space #\tab #\newline #\linefeed #\page #\return)))
>
> (defun constituent-or-escape-p (ch)
> (and (not (get-macro-character ch))
> ;; order important.
> (not (whitespacep ch)))
>
> (defun read-delimited-list (ch &optional (stream *standard-input*)
> recursivep)
> (let ((result '()))
> (loop
> (let ((next (peek-char nil stream)))
> (cond ((char= next ch)

(read-char stream) ; then the character is consummed!

> (return (nreverse result)))
> ((let ((mc (get-macro-character next)))
> (when mc
> (let ((objects (multiple-value-list (funcall mc stream (read-char stream)))))
> (when objects
> (push (first objects) result)))
> t)))
> ((constituent-or-escape-p next)
> (push (read stream t nil recursivep) result))
> (t ; whitespace
> (read-char stream)))))))
>
> (with-input-from-string (in "a b d)")
> (read-delimited-list #\) in))
> (a b d)
>
> (with-input-from-string (in "a '(a b c) #(1 2 3) b d)")
> (read-delimited-list #\) in))
> (a '(a b c) #(1 2 3) b d)
>
> (princ (nth-value 1 (ignore-errors
> (with-input-from-string (in "a b . d)")
> (read-delimited-list #\) in)))))
> Reader error on #<string-input-stream :closed #x30200232C20D>:
> Dot context error in ".".#<ccl::simple-reader-error #x302002328C4D>

--
__Pascal Bourguignon__

Kaz Kylheku

8/9/2015 3:15:00 AM

0

On 2015-08-08, Taoufik Dachraoui <dachraoui.taoufik@gmail.com> wrote:
>> Kaz wrote:
>> The read-delimited-list function doesn't handle dotted lists like (1 2 . 3).
>
> But the follwoing test shows that it does:
>
> ? '(a b .3 . (c .4 (d e .5 . ((0.6 . 0.7))) .8))
> (A B 0.3 C 0.4 (D E 0.5 (0.6 . 0.7)) 0.8)

The only problem is that the ANSI CL description of read-delimited-list doesn't
require the above behavior.

Clozure Common Lisp on Windows:

? (read-delimited-list #\))
1 2 3 4 . 5)
(1 2 3 4 . 5)

No problem here. How about CLISP?

[1]> (read-delimited-list #\))
1 2 3 4 . 5)

*** - READ from #<IO TERMINAL-STREAM>: token "." not allowed here
The following restarts are available:
ABORT :R1 Abort main loop
Break 1 [2]>

Oops!

According to ANSI CL (as seen in the HyperSpec), read-delimited-list reads
*objects* until the delimiter character is seen. The consing dot token
doesn't denote an object, though.

The period character . is a constituent. This means that . is a token.

See: 2.3.3 Consing Dot; and 2.4.1 Left Parenthesis.

2.4.1 describes a requirement for recognizing consing dot tokens, which is not
present in the description of read-delimited-list.

Marco Antoniotti

8/9/2015 6:24:00 AM

0

On Saturday, August 8, 2015 at 1:16:38 PM UTC+3, Taoufik Dachraoui wrote:
> > Kaz wrote:
> > The read-delimited-list function doesn't handle dotted lists like (1 2 . 3).
>
> But the follwoing test shows that it does:
>
> ? '(a b .3 . (c .4 (d e .5 . ((0.6 . 0.7))) .8))
> (A B 0.3 C 0.4 (D E 0.5 (0.6 . 0.7)) 0.8)
>
> ? '(a .x b .3 . (c .x .4 (d .x e .5 . ((0.6 .x . 0.7))) .8 .x))
> (A B 0.3 C 0.4 (D E 0.5 (0.6 . 0.7)) 0.8)
>
> -Taoufik



Dear Taoufik,

all of this is interesting and cute. And the previous discussion (and the following) full of nice insights.

However:

1 - CL has properly nested comments with the pair #| ... |# (you can do #| .. #| #| ... |# ... |# ... |# it works and you won't have /* ... /* ... */ surprises).

2 - It looks like you want your "disappearing one word comments" to inject syntax in code. Not so good an idea. You may end up not understanding my code (and me yours): to deal with syntax you use macros.

Cheers
--
MA

Taoufik Dachraoui

8/9/2015 12:46:00 PM

0

Hi

Using my intuition I supposed that
if the stream is equal to [lisp-objects* char lisp-objects*]
then (read-delimited-list char) is equivalent to
(read) when the stream is equal to [( lisp-objects* ) lisp-objects*]

I think it should have been defined recursively using read

Any way, I reimplemented the one-word-comment without using read-delimited-list as follows:

; one-word-comment without using read-delimited-list
(defvar *lpar-reader* (get-macro-character #\())

(defun lpar-reader (s c)
(set-macro-character #\( *lpar-reader*)
(unread-char c s)
(let ((a (read s t nil t)))
(labels ((foo (e)
(cond
((atom e) e)
((and (symbolp (car e))
(eq (char (symbol-name (car e)) 0) #\.))
(foo (cdr e)))
(t (cons (foo (car e)) (foo (cdr e)))))))
(prog1
(foo a)
(set-macro-character #\( #'lpar-reader)))))

(set-macro-character #\( #'lpar-reader)


> Marco Antoniotti wrote:
>all of this is interesting and cute. And the previous discussion (and the following) full of nice insights.
>
>However:
>
>1 - CL has properly nested comments with the pair #| ... |# (you can do #| .. #| #| ... |# ... |# ... |#
>it works and you won't have /* ... /* ... */ surprises).
>
>2 - It looks like you want your "disappearing one word comments" to inject syntax in code. Not so
> good an idea. You may end up not understanding my code

(if pred .then code .else else)
is same as
(if pred #|then|# then #|else|# else)

The one-word-comment is just a comment but instead of using #|foo|# we use .foo, I do not think
that this will make the code less understandable.

Kind regards

-Taoufik