> You don't have to crack open a reference manual to look at grammar rules or precedence tables to work out what the shape of the syntax tree is; you can read anything just from the symbolic prefix, plus a smattering of minor notations like sharpsign-this and sharpsign-that.
You can't. Any macro may support arbitrary syntax. If all you know is the macro name, you don't know nothing about the syntax it implements.
> (foo (x y) (z w))
There are many many much more complex forms in Lisp.
> And words have the nice property that you can look them up easily in manuals
Then you need to know the set of precedence order names. What is a GF-DECLARACTION?
What is a method-qualifier? what is the specialized-lambda-list? What are valid declaration expressions...?
> Those who say Lisp is not readable are trolls and liars.
I don't think you add credibility with these statements. Sorry, this is just dumb.
Even though macros can contain any syntax, and in principle we can have a macro such that:
(mac token1 token2 token3 ... tokenN)
where the tokens are parsed according to some LALR(1) (or worse) grammar, in practice, macros are usually not designed that way. The nested list syntax is used for grouping units together.
So without knowing what mac is, you don't know the semantics, but the structure is, more often than not, crystal clear.
Of course you need the manual to know what they mean if you don't remember (gee, which is the class name and which is the instance, location or point?), but you don't have to implement the LARL(1) parser in your head.
Which of the following forms are valid Common Lisp:
(defun foo (a b)
(declare (fixnum a))
"foo"
(declare (fixnum b))
(+ a b))
(defun foo (a b)
"foo"
(declare (fixnum a))
(declare (fixnum b))
(+ a b))
(defun foo (a b)
(declare (fixnum a))
(declare (type fixnum b))
"foo"
(+ a b))
(defun foo (a b)
(declare (type fixnum b))
"foo"
"bar"
(declare (fixnum a))
(+ a b))
(defun foo (a b)
(declare (fixnum a))
(declare (type fixnum b))
"foo"
"bar"
(+ a b))
(defun foo (a b)
(declare (fixnum a))
"foo"
"bar"
(+ a b))
I seem to be vaguely convinced for some reason that there may be exactly one docstring, and that, if present, it must be the first item in the body; then there can be declarations. Not sure if there can be two or more declares. I would always write (declare (fixnum a) (fixnum b)) and don't recall seeing multiple declares in other people's code. (I might be suffering from a form of amnesia which merges multiple ANSI Lisp declares into one.)
This is the sort of thing I'd look into closely if I were tasked with parsing a function body (like for the sake of making some body rearranging-and-reassembling macro fully conforming with the surrounding language). I'm not going to write such code myself, and won't likely see it in other people's code.
Until I see such instances, I won't bother looking at the spec to see what the exact rules are and confirm/refute whether those examples are conforming.
In any case, whether or not some of the examples are correct, I can see what they are trying to say. Be they mistakes, they are still well-formed surface syntax and are readable. Things could plausibly work in some CL dialect such that they are all correct, if they aren't.
A literal string near the beginning of a function, which is only evaluated for its side effect (which it doesn't have) looks suspiciously like a doc string. Either it is correctly positioned or it isn't. The (declare ...) syntax is clearly a declaration, whether or not correctly positioned. (declare ...) isn't a form. I suspect it would be undefined behavior for a program to define a function or macro called declare; not sure about that. Defined or not, it would be a incredibly bad idea.
I'm a competent Lisp programmer and implementor too, and don't have to have this memorized; it's likely not an impediment to anyone else. Which kind of makes my point.
A Lisp programmer has to care, if he wants to write Lisp code.
> I seem to be vaguely convinced for some reason that there may be exactly one docstring, and that, if present, it must be the first item in the body
That's wrong.
> I won't bother looking at the spec to see what the exact rules are
Which confirms what I'm saying: even for seemingly trivial DEFUNs the syntax is not obvious.
> Be they mistakes, they are still well-formed surface syntax and are readable.
But the reader does not implement Lisp syntax. The reader just implements s-expression syntax. If the reader can read the form, then it is a valid s-expression. But not necessarily valid Lisp.
(defun foo (a) a) ; valid s-expression, valid Lisp
(defun (foo) a a) ; valid s-expression, not valid Lisp
(defun (bar foo) (a) a) ; valid s-expression, not valid Lisp
(defun (setf foo) (a) a) ; valid s-expression, valid Lisp syntax
(defun foo (&key a &optional b) (list a b)) ; not valid Lisp
(defun foo ($key a &optional b) (list a b)) ; valid Lisp
The Lisp interpreter/compiler and the macros implement Lisp syntax. Not the reader.
> it's likely not an impediment to anyone else.
That you don't know the syntax of DEFUN confirms what I'm saying: the syntax is non-obvious.
Explain this:
* (defun foo (a b)
(declare (fixnum a))
"foo"
"bar"
(+ a b))
debugger invoked on a SIMPLE-ERROR: duplicate doc string "bar"
Type HELP for debugger help, or (SB-EXT:EXIT) to exit from SBCL.
restarts (invokable by number or by possibly-abbreviated name):
0: [ABORT] Exit debugger, returning to top level.
(SB-INT:PARSE-BODY ((DECLARE (FIXNUM A)) "foo" "bar" (+ A B)) T NIL)
0]
> That you don't know the syntax of DEFUN confirms what I'm saying.
Yes, it rather confirms that you can go far in Lisp without memorizing stuff like this!!!
If I don't have to know, few people do.
You can bet your ass that if I had to implement an ANSI-CL conforming defun/lambda I'd get it right, of course. I don't have some "requirements don't matter" attitude; but not all requirements matter all the time to all people.
I'd like to add, though, this: you can't be safe in ignorance in Common Lisp. Things you don't know can hurt you. Less than in some other languages, but they are there. You probably won't be hurt by not knowing all the possibilities for combining docstrings and declares. But if you're ignorant of some things, you may get burned. Undefined behavior situations like modifying literal tree structure, or writing a program that parses untrusted Lisp data, not knowing about the #. syntax and * read-eval* . I'm not advocating unsafe ignorance. Not knowing the full flexibility of some syntax is generally safe, though.
> Explain this:
Which aspect of that error scenario isn't self-explanatory; what is left to explain?
From that one error, the listener has just taught us several important facts about the syntax which it accepts (which may be a superset of ANSI CL for all we know). It shows us that it accepts a docstring after a declare just fine, but that there must be at most one docstring. (At least, when the two are in that order, if we are to be strict in our guessing.)
So without looking at a shred of documentation outside of that error message, I'm already better informed.
The interactive nature of Lisp teaches! (Especially if the implementation is tight on error checking and has good diagnostics.)
What's left unsettled from that error situation is whether or not there may be multiple declares, since that case isn't being probed.
Which says: any number of declarations and at most one documentation, in any order.
(defun foo (a b)
(declare (fixnum a)) ; declaration
"foo" ; documentation
"bar" ; form
(+ a b))
Which indicates that SBCL rejects a valid program. I would not trust you to get it right as an implementor, given that you haven't even tried to verify it and that you are ignorant to Lisp syntax. I would not trust my own implementation without trying to come up with an extensive syntax test suite.
Hi lispm. I investigated this more deeply and I'm afraid I cannot conclude that SBCL is wrong.
The root of the problem is this splicing [[ ]] extended BNF notational concoction, in whose description we find this:
... For example, the expression
(x [[A | B* | C]] y)
means that at most one A, any number of B's, and at most one C can occur in any order. It is a description of any of these:
(x y)
(x B A C y)
(x A B B B B B C y)
(x C B A B B B y)
but not any of these:
(x B B A A C C y)
(x C B C y)
In the first case, both A and C appear too often, and in the second case C appears too often.
In the case of defun, we can identify C with documentation and y with forms. But documentation is a kind of form. According to the above, if we are given documentation documentation form, it doesn't match: documentation appears "too often". That appears to rule out "foo" "bar" as ill-formed, if "bar" is interpreted as documentation rather than form.
This is woefully badly specified; it is not clear how to unambiguously determine the extent of the symbols matched by a given [[ ]] notation.
There needs to be a clearly stated requirement that [[ ]], independently of what follows it, denotes (say) the longest possible sequence of symbols which is consistent with its constraints. The material which follows [[ ]] must then match against the remaining symbols in the form. Then it will be clear that given "foo" "bar", the "bar" string isn't part of the [[ declare(star) | documentation ]] spec, because the longest match ends with "foo" (if no declares follow).
Maybe it does. I'm afraid I cannot make head or tail out of the sentence "such that if n /=m and 1<=n,m<=j, then either Oin/=Oim or Oin = Oim = Qk, where for some 1<=k <=n, Ok is of the form Qk {star} . Furthermore, for each Oin that is of the form {Qk}1 , that element is required to appear somewhere in the list to be spliced. " Perhaps that rescues it somehow.
Why not? A code review has topics. It could be to enforce a coding convention.
Firstly, I would not pass code that uses multiple docstrings or a funny order for docstrings and declares or multiple declares; a coding convention should forbid such pointless shenanigans, whether or not they are ANSI conforming.
If the topic of the review was to determine whether the code is ANSI CL conforming, then I wouldn't just feed it to the listener of SBCL or any other implementation. Obviously, implementations can be nonconforming. They can accept, without diagnostic, inputs that require a diagnostic, as well as inputs that are nonportable or entirely undefined.
You can't determine conformance of the code, or of the implementation, or both, without reading and interpreting the applicable standard, obviously. (You didn't have to labor this far if you just wanted me to say that.)
> Does SBCL implement the syntax correctly or does it reject valid programs?
Even if we determine that SBCL is rejecting valid programs, that version of SBCL will forever continue to do so. We have to change to a working construct to get the code working.
Once we do that, the status of the nonworking construct that we replaced with a working one is rather moot. We have found all instances of that construct and replaced it, after which it no longer occurs in our code.
We may submit a bug report against SBCL. Since we fixed the code not to interact with the bug/noncompliance, we don't care when, if ever, SBCL issues a fix.
The nonworking construct could have been avoided in the first place by sticking to the simplified "canonical" syntax:
You can program defun-s for the rest of your Lisp programming life this way and never know the full syntax. You're also vanishingly unlikely to run into an implementation which doesn't accept the variations on this canonical syntax.
Deviations from this form can be rewritten into this form.
The exception might be machine-generated deviations. Like multiple declares or docstrings that are piled on by some macrology: if you want their output to be canonicalized, you have to insert some processing pass to do that normalization. That is annoying, and so we will feel better if we can blame it on a nonconformance in the implementation, even if we still have to do this work.
> (defun foo () "a" "b" "c") ; sbcl rejects
That's somewhat nasty; yet, there is no reason to write this kind of defun by hand. "a" is obviously a docstring, and "c" the return value. But "b" is superfluous in the sense that it has no effect.
If "b" contains documentation, it should be merged into "a" to produce the canonical form (defun foo () "ab" "c"): "ab" is the doc, "c" the returned object. If that doesn't work, then I care; that is uproarious.
I might be interested in knowing whether the above "a" "b" "c" is in fact invalid ANSI CL, if I'm more invested in that rejected form; like I have some macrology that produces it (so fixing the situation requires more work than just hunting down a couple of bad defuns). That macrology could be reused in other projects and so on.
Still, the fact that SBCL rejects it means that I can't have it if we are targetting SBCL. A workaround for SBCL (if that's what it is) might as well be applied all across the board.
This [[]] notation is a special "splicing" extension of the BNF syntax which here indicates that there may be at most one docstring and any number of declarations, and these may appear in any order (so that a docstring can come between declares).
I was talking about DEFGENERIC syntax, not a trivial example of DEFGENERIC/DEFMETHOD.
> Even though macros can contain any syntax...practice, macros are usually not designed that way.
The LOOP and ITERATE macros are examples of macros with lots of syntax.
> So without knowing what mac is, you don't know the semantics, but the structure is, more often than not, crystal clear.
The syntax of DECLARE, DEFGENERIC, HANDLER-CASE, HANDLER-BIND, DEFINE-CONDITION, DEFINE-METHOD-COMBINATION, LOOP, FORMAT, ... are far from 'crystal clear'.
One of the macros which is very hard to get right and to understand what it actually does is CLIM:DEFINE-APPLICATION-FRAME
You can't. Any macro may support arbitrary syntax. If all you know is the macro name, you don't know nothing about the syntax it implements.
> (foo (x y) (z w))
There are many many much more complex forms in Lisp.
> And words have the nice property that you can look them up easily in manuals
Then you have to read the syntax FOO implements.
DEFGENERIC:
Then you need to know the set of precedence order names. What is a GF-DECLARACTION? What is a method-qualifier? what is the specialized-lambda-list? What are valid declaration expressions...?> Those who say Lisp is not readable are trolls and liars.
I don't think you add credibility with these statements. Sorry, this is just dumb.