aarons@syma.sussex.ac.uk (Aaron Sloman) (09/13/90)
It's interesting to see this debate surface yet again. Jeff Dalton writes > In my experience, in both the US and the UK, it is true that students > often make quoting mistakes in Lisp and that they often find the > quoting rules confusing. I think there are a number of possible > contributing factors. > > A common mistake in presentation, I think, is to make non-evaluation > seem too much of a special case. For example, some people see SETQ as > confusing because it evaluates one "argument" and not another and so > they prefer to present SET first. .... > > Indeed, the whole terminology in which SETQ, COND, etc. are presented > as funny kinds of "functions" and where functions are described as > "evaluating an argument" (or not) may be a mistake. It wasn't till I read this remark of Jeff's that I realised that one reason I don't like Lisp is that, apart from "(" and ")", Lisp doesn't help one to distinguish syntax words and function names. Actually, as a sort of failed mathematician, I do appreciate the elegance and economy of lisp syntax and could probably even like using some versions (i.e. T or Scheme, though not Common Lisp). But for teaching most of the kinds of students I have met I would far rather use Pop-11 which, in many ways, is similar to, and owes a great deal to, Lisp, though its syntax is much more redundant. (There are other differences that are irrelevant to this discussion.) In teaching Pop-11 I always try to get students to think in terms of a distinction between (a) "syntax" words (e.g. the assignment arrow "->", parentheses, list brackers "[", "]", "if", "endif", "for", "endfor" "while", "define" etc.) and (b) words that represent procedures (this includes functions and predicates, which return results, and subroutines, which don't). Most of its syntax forms have distinctive opening and closing brackets, e.g. "for" ... "endfor", "define" ... "enddefine" etc. This is verbose and inelegant but it helps learners to grasp the sort of distinction (I think) Jeff is making. There are exceptions, like the assignment arrow "->" which looks just like an infix procedure name, but since students don't naturally class it with the infix operators they already know (i.e. the arithmetic operators) they easily accept it as a different kind of beast, playing a special and important role in their programs. (Actually taking something from the stack and putting it somewhere, or running procedure "in updater mode"). Another kind of exception that helps to muddle the distinction is the use of special brackets for constructing lists and vectors [a list of words] {a vector of words} The brackets have both a syntactic role (delimiting expressions) and also implicitly identify functions that return results. Again these are very special forms that are easily learnt as special cases. (Natural languages are full of special cases: the human brain seems good at coping with lots of special cases.) By contrast the uniform syntax of lisp makes it not so easy to grasp that car, cdr, sqrt, append, etc. are different beasts from setq, cond, quote, loop, etc. Hence the tendency to make the kind of mistake that Jeff describes, i.e. talking about different kinds of functions. It should be possible to investigate this conjecture about lisp syntax causing more confusion empirically. I wonder if anyone has? Moreover, the syntactic redundancy involved in using different closing brackets for each construct in Pop-11 really does make it much easier for many readers to take in programs, which is parly analogous to the reasons why modern lisp programmers eschew the syntactic economy of APL programmers and use long and redundant procedure names in this sort of style (sum_of_squares_of x y) rather than (ssq x y) Having extra syntactic redundancy also makes it easier to provide helpful compile time checks and error messages, e.g. if an editing mistake produces if isinteger(x) else foo(y) endif the compiler will complain: MISPLACED SYNTAX WORD : FOUND else READING TO then which can be especially helpful where sub-expressions are more complex. > Steve wrote > >Obviously, the attractiveness of syntax is in the eye of the beholder. > >I have to accept that folks like Jeff are sincere when they argue that the > >syntax of Lisp is very attractive for them. (I am even inclined to agree > >when the alternative is C++.) Jeff replied > I would agree, provided we don't take this "eye of the beholder" > stuff too far. It's true that different people will prefer different > syntaxes and that we can't say they're wrong to do so. However, we > shouldn't go on to conclude that all views on the virtues or otherwise > of a syntax are equally valid. Sometimes we can say, for example, > that someone hasn't learned good techniques for reading and writing > code in a particular syntax and that's why they find it so hard > to read and write. I agree. It should also be possible to spell out precisely the cognitive requirements for particular kinds of learners and users at particular stages in their development, or for particular kinds of programming tasks, and establish the strengths and weaknesses of alternative languages by argument and evidence and not by simply agreeing to differ. E.g. the use of essentially redundant keywords like "then", "elseif" and "else" in conditionals, and the use of distinct closing brackets like "endif", "endwhile" that remind you what sort of construct they are terminating, has a particularly important consequence. It reduces short term memory load, and allows local attention focussing, by providing local cues or reminders as to the nature of the context, whereas without them one has to parse a larger expression to know that something plays the role of a condition, or a consequent. (Some lisp constructs also use these extra keywords, e.g. "for" ... "from" ... "to". So the fault is one of degree.) The point about memory load is an objective fact. Whether it matters for a particular user is going to depend on the kinds of cognitive skills that user has already developed. It's a bit like the question whether you should repeat the key signature at the beginning of every line in a musical score, or simply indicate it when the key changes. For certain experienced musicians the economical method will suffice. For most ordinary mortals the frequent reminder is useful, even if it does increase the clutter on the page and probably the printing costs! Note that the time signature is not usually repeated on every line because that is (mostly) evident from the contents of each bar, or at least determined to within a small range of alternatives. Another analogy is with the difference between the musical annotation "crescendo al fine" (= get louder from here to the end), which requires the reader to remember the instruction from there on, and the alternative notation which has a pair of lines getting further and further apart, immediately above or below the stave, as a _continual_ reminder that you have to be getting louder. For many would be performers the first form will not be as effective as the second. Exactly how important all these differences in syntactic redundancy and memory load, etc. are, and in what way, will to some extent remain unsettled until we have good theories describing the various kinds of cognitive processes that go on in various kinds of people when they read, or write, or design, or debug, programs. But most designers of programming languages don't think about human cognitive processes. Aaron Sloman, School of Cognitive and Computing Sciences, Univ of Sussex, Brighton, BN1 9QH, England EMAIL aarons@cogs.sussex.ac.uk
ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) (09/14/90)
In article <3450@syma.sussex.ac.uk>, aarons@syma.sussex.ac.uk (Aaron Sloman) writes: > It's interesting to see this debate surface yet again. > It wasn't till I read this remark of Jeff's that I realised that one > reason I don't like Lisp is that, apart from "(" and ")", Lisp > doesn't help one to distinguish syntax words and function names. I once built a programming language which was a sort of hybrid between Lisp and Pop. In RILL, one wrote e.g. $IF (> X Y) $THEN (SETQ MAX X) $ELSE (SETQ MAX Y) $FI Basically, I used keywords for control structures ($PROC for lambda, $BEGIN for let, $IF, $FOR, $WHILE, and so on) and Lisp syntax for the rest. The parser _was_ better able to notice typing mistakes, and I _did_ make far fewer parenthesis errors than I did with straight Lisp when I later got my hands on it. But that was before I met Emacs. > By contrast the uniform syntax of lisp makes it not so easy to grasp > that car, cdr, sqrt, append, etc. are different beasts from setq, > cond, quote, loop, etc. Hence the tendency to make the kind of > mistake that Jeff describes, i.e. talking about different kinds of > functions. The thing about Pop (as it was last time I used it) is that there is no defined internal form for code. At one end of the spectrum we have "token stream" and at the other end we have "compiled code", and there is nothing in between. I don't know how Pop-11 handles it these days, but in WonderPop the easiest way to write a macro was e.g. form for x:id in e:expr do s:stmts enddo; formvars L; vars L; e -> L; while L.null.not do L.dest -> x -> L; s enddo endform which is roughly the equivalent of (defmacro for (x e &rest s) (let ((L (gensym))) `(do ((,L ,e (cdr ,L))) ((null ,L)) (setq ,x (car ,L)) ,@s))) but it worked rather differently. When the parser found the keyword 'for' it would call the function defined by the form. That function would call .readid to read the identifier for x. It would then check that the next token was "in". It would then call .readexpr to read the expression e. It would then check that the next token was "do". It would then call .readstmts do read the body s. It would then check that the next token was "enddo". Then it would start on the expansion. If any of the reads or tests failed, it would backtrack and try another form (any number of forms could start with the same keyword). What were x, e, and s bound to? *lists of tokens*. The body of the form was processed by making a list of tokens and pushing the lot back on the input token stream. I'm sure I have the names of the reading functions wrong, but that's basically how macros worked in WonderPop, as transformations of sequences of tokens. It works very well. I found Pop "forms" easy to use. But macros aren't the only use for an internal representation. There was no debugging interpreter, for example. (Though you could quite easily trace functions.) > It should also be possible to spell out precisely the cognitive > requirements for particular kinds of learners and users at > particular stages in their development, or for particular kinds of > programming tasks, and establish the strengths and weaknesses of > alternative languages by argument and evidence and not by simply > agreeing to differ. Agreed! > But most designers of programming languages don't think about human > cognitive processes. You should read C.J.Date's comments on SQL... -- Heuer's Law: Any feature is a bug unless it can be turned off.
jeff@aiai.ed.ac.uk (Jeff Dalton) (09/15/90)
In article <3450@syma.sussex.ac.uk> aarons@syma.sussex.ac.uk (Aaron Sloman) writes: >It wasn't till I read this remark of Jeff's that I realised that one >reason I don't like Lisp is that, apart from "(" and ")", Lisp >doesn't help one to distinguish syntax words and function names. Actually, Pop-11 doesn't do much along those lines either. It's not like it uses a different font for them (cf Algol). >Moreover, the syntactic redundancy involved in using different >closing brackets for each construct in Pop-11 really does make it >much easier for many readers to take in programs, >E.g. the use of essentially redundant keywords like "then", "elseif" >and "else" in conditionals, and the use of distinct closing brackets >like "endif", "endwhile" that remind you what sort of construct they >are terminating, has a particularly important consequence. It >reduces short term memory load, [...] Now, there's no doubt soemthing to what you say. However, I don't think there's as much to it as you suppose. One of the *mistakes* some people make when writing Lisp is to try to add the redundancy you describe by putting certain close parens on a line of their own followed by a comment such as " ; end cond". It makes the code *harder* to read, not easier. People just starting to use Lisp, and people who use editors without a good Lisp mode (which at least used to include the PopLog editor that comes with Pop-11), may well find it helpful; but experienced Lisp programmers generally do not. Lisp procedures should be fairly short and indented so that it's easy to see the scope of a construct: everything up to the next line not indented more to the right. Putting in lots of end markers makes this harder to see, and short-term mempory doesn't have much problem keeping track. Of course, it's no doubt possible to write procedures (such as ones that are too long) where end markers might make a difference. But is is also possible to avoid those cases, just as it is possible to avoid other bad practices. Moreover, if you want to argue for the advantages of distinct closing brackets it's not necessary to compare Pop-11 with Lisp. How about comparing it with a language that uses "begin" and "end" (or "{" and "}") for everything rather than "endif" "endwhile", etc.? I think there are too many other differences between Pop-11 and Lisp. -- Jeff
aarons@syma.sussex.ac.uk (Aaron Sloman) (09/16/90)
jeff@aiai.ed.ac.uk (Jeff Dalton) (14 Sep 90 20:21:11 GMT) commented on my remarks on the syntactic poverty of Lisp. (From me:) > >It wasn't till I read this remark of Jeff's that I realised that one > >reason I don't like Lisp is that, apart from "(" and ")", Lisp > >doesn't help one to distinguish syntax words and function names. > (From Jeff:) > Actually, Pop-11 doesn't do much along those lines either. > It's not like it uses a different font for them (cf Algol). I agree that Pop doesn't make the syntax words look different in isolation. That wasn't what I meant (though perhaps that would be a good idea especially in printed text). Rather, I meant that in Pop-11 the syntax words (or many of them) play an obviously different role in syntactic constructs, e.g. having matching brackets and associated keywords. This helps students grasp that they have a different role from function names ie. they are concerned with how program text is grouped into sub-structures with (e.g.) control relations between them (evaluating THIS expression determines whether THAT one is executed, or whether iteration continues, etc.) Getting a good conceptual understanding of all this takes students some time. Using collections of related syntax words that indicate different kinds of syntactic "fields" or "contexts" in program text, seems to help. (I now think this is more than just an aid to short term memory as suggested in my earlier message. But the point needs more thought.) > .... (From me:) > >E.g. the use of essentially redundant keywords like "then", "elseif" > >and "else" in conditionals, and the use of distinct closing brackets > >like "endif", "endwhile" that remind you what sort of construct they > >are terminating, has a particularly important consequence. It > >reduces short term memory load, [...] (From jeff:) > Now, there's no doubt soemthing to what you say. However, I don't > think there's as much to it as you suppose. > > One of the *mistakes* some people make when writing Lisp is to > try to add the redundancy you describe by putting certain close > parens on a line of their own followed by a comment such as > " ; end cond". It makes the code *harder* to read, not easier. (He goes on to justify this by saying that indentation plus a good editor helps, and that GOOD lisp programs have short procedure definitions and that adding such comments makes them longer and harder to take in.) > Of course, it's no doubt possible to write procedures (such as ones > that are too long) where end markers might make a difference. But > is is also possible to avoid those cases, just as it is possible to > avoid other bad practices. I agree that a good editor helps a lot (though people often have to read code without an editor, e.g. printed examples in text books, etc) and I agree that well-written short lisp definitions (e.g. up to five or six lines) are often (though not always) easily parsed by the human brain and don't need much explanatory clutter. But I doubt that it is always desirable or possible to build good programs out of definitions that are short enough to make the extra contextual reminders unnecessary. It probably depends on the field of application. E.g. I suspect that in symbolic math programs you can get away with lots of short procedures, whereas in graphics, vision, operating system design, compilers(??) and building complex interactive programs like text editors and formatters, some at least of the procedures are going to have longish stretches of nested case analysis, several nested loops, etc. Even Common_Lisp_The_Language (second edition) has examples that I think are long enough to benefit from these aids that you say are unnecessary. (Scanning more or less at random for pages with lisp code, I found examples on pages 340-349, 667, 759, 962 and 965. Or are these just examples of bad lisp style? (I've seen much worse!) > > Moreover, if you want to argue for the advantages of distinct closing > brackets it's not necessary to compare Pop-11 with Lisp. How about > comparing it with a language that uses "begin" and "end" (or "{" and > "}") for everything rather than "endif" "endwhile", etc.? Yes, Pascal and C (especially C) are open to some of the same objections as lisp, because they don't have sufficient disinct opening and closing brackets, though the use of "else" is a step in the right direction. This is why many programmers using these languages add the kinds of comments you disapprove of. (Some Pop-11 programmers do also.) ML is another language which, from my observations and reports of student difficulties, has a syntax that is too economical, though in a very different way from Lisp. I don't know the language well, but I think it requires the reader to depend too much on remembered operator precedences in different contexts. This is no problem for a computer but very hard for people. So students often have great trouble understanding how compile-time error messages relate to the code they have written, which "looks" obviously right to them. Additional use of brackets might help. (Perhaps this syntactic poverty will prevent ML ever being used widely for large scale software engineering.) Prolog has yet another kind of syntactic poverty, inherited from its dependence on a logical interpretation. (E.g. textual order has very different procedural meanings depending on context: within a rule concatenation means something like "and then", whereas between rules with the same predicate it means something like "and if that fails then try...") My general point is that human perception of complex structures is easiest and most reliable when there is well chosen redundancy in the structures, and most difficult and error-prone when there isn't. However, as you point out, too much redundancy can sometimes get in the way, and we don't yet know the trade-offs. The use of indentation in lisp and C is an example of redundancy that is an essential aid for humans although totally unnecessary in theory. But it is only one type of redundancy, and is useful only on a small scale (as you imply). (Maybe this stuff should have been cross-posted to comp.cog-eng, since cognitive engineering is what we are talking about.) For the record, I should also say that I don't think there's much difference in readability between the following: a(b(c(d, e), f(g, h))) [Pop-11 and Pascal, etc] (a (b (c d e) (f g h))) [Lisp] Though I do find the latter more visually elegant. > I think > there are too many other differences between Pop-11 and Lisp. Yes, there are other differences, including the differences mentioned by Richard O'keefe to which I'll respond in another message. Aaron
aarons@syma.sussex.ac.uk (Aaron Sloman) (09/16/90)
ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) (14 Sep 90) Organization: Comp Sci, RMIT, Melbourne, Australia Richard commented on my comments on Jeff Dalton's remarks about Lisp. (From me) > > It wasn't till I read this remark of Jeff's that I realised that one > > reason I don't like Lisp is that, apart from "(" and ")", Lisp > > doesn't help one to distinguish syntax words and function names. > (From Richard) > I once built a programming language which was a sort of hybrid between > Lisp and Pop. In RILL, one wrote e.g. > $IF (> X Y) $THEN (SETQ MAX X) $ELSE (SETQ MAX Y) $FI > Basically, I used keywords for control structures ($PROC for lambda, > $BEGIN for let, $IF, $FOR, $WHILE, and so on) and Lisp syntax for the rest. > The parser _was_ better able to notice typing mistakes, and I _did_ make > far fewer parenthesis errors than I did with straight Lisp when I later > got my hands on it. But that was before I met Emacs. > > > By contrast the uniform syntax of lisp makes it not so easy to grasp > > that car, cdr, sqrt, append, etc. are different beasts from setq, > > cond, quote, loop, etc. Hence the tendency to make the kind of > > mistake that Jeff describes, i.e. talking about different kinds of > > functions. > > The thing about Pop (as it was last time I used it) is that there is > no defined internal form for code. At one end of the spectrum we have > "token stream" and at the other end we have "compiled code", and there > is nothing in between. > ..... Nowadays, at least in Poplog, there is the Poplog virtual machine (PVM) in between, but that is still not easy for user programs to get hold of, and in any case it is still not the sort of thing you want. The lack of something like a well defined internal parse tree structure for Pop-11 is both a great weakness and a great strength. It is a weakness because it limits the ability of programs to analyse Pop-11 programs and makes debugging aids harder to build. It also makes macros harder to write: you have to read in a "flat" sequence of text items, then replace it on the input list with a new sequence, instead of being able to reorganise a parse tree (though pattern matching utilities of the sort described in your letter can help). It (lack of a defined internal form) is a strength because Pop-11 (unlike older versions of Pop) provides an alternative to writing macros. I.e. you can define a syntactic extension by creating a syntax word that reads in text and then plants instructions for the PVM. You are not restricted to extensions that map onto what the Pop-11 compiler can handle, as you would be with macros. A syntax word can plant any code that makes sense for the PVM, which provides a richer range of possibilities. Just to illustrate, the PVM can support ML and Prolog as well as Pop-11 and Common Lisp. PVM instructions get compiled to machine code. Could a compiled ML or Prolog be defined using Lisp macros? The lack of a defined internal form enhances extendability: if there were a defined internal form you could not create an extension that did not map onto that form. (I am assuming that any internal form that is "high level" enough to be useful in the way you want is going to be more restrictive than the PVM. I don't know how to prove this!) It may be possible to have some sort of compromise: a core language with a defined internal form, with extensions permitted that don't have to map onto it. I have no idea how feasible this would be. (From me) > > But most designers of programming languages don't think about human > > cognitive processes. > (From Richard) > You should read C.J.Date's comments on SQL... Perhaps you should post a reference and a summary??? Aaron
jjacobs@well.sf.ca.us (Jeffrey Jacobs) (09/18/90)
> closing brackets
Back in the good 'ol days, when we had to slog through 10 feet of snow
to get to our glass TTYs, we had another level of parentheses, consisting
of [,] and <esc>. "]" closed off all open "(" or an open "["; <esc>
closed off all open "(" and/or "[".
Jeffrey M. Jacobs
ConsArt Systems Inc, Technology & Management Consulting
P.O. Box 3016, Manhattan Beach, CA 90266
voice: (213)376-3802, E-Mail: 76702.456@COMPUSERVE.COM
gumby@Cygnus.COM (David Vinayak Wallace) (09/18/90)
Why is it good to make a distinction between "syntax words" and "function names?" Sure you need to understand the semantics of QUOTE before you use it, but then again you need to understand the semantics of PLUS (as has been ably pointed out) before you use it, too. Personally, the thing that drives me up the wall about non-lispy languages like C is the artificial distinction between "expressions" and "statements." Apart from making it harder for me to think about my code, they don't let me tell my compiler various things it ought to know (by, for instance, requiring that I make lots of assignments).
ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) (09/18/90)
In article <3427@skye.ed.ac.uk>, jeff@aiai.ed.ac.uk (Jeff Dalton) writes: > In article <3450@syma.sussex.ac.uk> aarons@syma.sussex.ac.uk (Aaron > Sloman) writes: > >It wasn't till I read this remark of Jeff's that I realised that one > >reason I don't like Lisp is that, apart from "(" and ")", Lisp > >doesn't help one to distinguish syntax words and function names. > Actually, Pop-11 doesn't do much along those lines either. > It's not like it uses a different font for them (cf Algol). Come come. All that's needed for that is a suitable vgrind(1) description. Surely there must be one available already; Pop-11 syntax is close enough to Pascal/Modula syntax for it to work. (I must admit that Interlisp-D's editors did a nice job of displaying functions with "keywords" and comments very clearly distinguished.) I've been marking some 2nd year Pascal assignments recently, and have come to the conclusion that Lisp programmers probably have _less_ trouble with parentheses. Pascal's precedence rules are so counterintuitive that people seem to throw in lots of parentheses just because they're never quite sure what Pascal will do to them if they're left out. At least in Lisp the rules are _simple_. -- Heuer's Law: Any feature is a bug unless it can be turned off.
ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) (09/18/90)
In article <3465@syma.sussex.ac.uk>, aarons@syma.sussex.ac.uk (Aaron Sloman) writes: > Prolog has yet another kind of syntactic poverty, inherited from its > dependence on a logical interpretation. (E.g. textual order has very > different procedural meanings depending on context: within a rule > concatenation means something like "and then", whereas between rules > with the same predicate it means something like "and if that fails > then try...") Not to defend Prolog syntax overmuch, but I had to stop and think for several minutes before I understood what Aaron Sloman was getting at here. It had never occurred to me that p :- % p <if> a, % a <and-then> b. % b. and p(a). % either p(a) p(b). % or-else p(b) were both "concatenation". For sequencing of clauses, yes it is plain juxtaposition. But and-then is an explicit operator ",", not mere concatenation. I have always experienced these two constructions as utterly different, and it is very hard for me to see them as similar. If we wrote (((p) ; p if (a) ; a and-then (b))) ; b and (((p a)) ; either p(a) ((p b))) ; or-else p(b) _then_ we would be using juxtaposition of lists for both. > For the record, I should also say that I don't think there's much > difference in readability between the following: > a(b(c(d, e), f(g, h))) [Pop-11 and Pascal, etc] > (a (b (c d e) (f g h))) [Lisp] I was about to agree, and then I suddenly realised that I find the second distinctly easier to read. Hang on a minute, I'm a _Prolog_ programmer, what's going on here? Just for fun, here's a Pop-2 statement that does the same function calls: d, e.c, g, h.f.b.a; Not to knock Pop. If Scheme is the Messiah, Pop is John the Baptist. [It's a _joke_, Joyce.] -- Heuer's Law: Any feature is a bug unless it can be turned off.
ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) (09/18/90)
In article <3466@syma.sussex.ac.uk>, aarons@syma.sussex.ac.uk (Aaron Sloman) writes: > It (lack of a defined internal form) is a strength because Pop-11 > (unlike older versions of Pop) provides an alternative to writing > macros. I.e. you can define a syntactic extension by creating a > syntax word that reads in text and then plants instructions for the > PVM. Was it Madcap that used to do that? > Could a compiled ML or > Prolog be defined using Lisp macros? Yes. All you have to do is provide appropriate syntactic forms for the macros to expand into. In Interlisp-D, for example, it would be quite straightforward. It's not the *top* level that's special here, it's the *bottom* level. > The lack of a defined internal form enhances extendability: if there > were a defined internal form you could not create an extension that > did not map onto that form. But if every PVM instruction were available as a construct that could appear in text, there would be no such extension possible. For example, in many C compilers, there is no assembly code program which cannot be generated by that compiler, because there is an asm() construct which can be used to generate the instruction of your choice. Nearer "home" (in the sense that it is more like the way suitable Lisp compilers work) the Sun C compilers use ".il" files which let you map what looks like a function call to the instructions of your choice, and peephole optimisation happens after such expansion. It's the _bottom_ level that matters here. [Aaron Sloman] > But most designers of programming languages don't think about human > cognitive processes. [Richard O'Keefe] > You should read C.J.Date's comments on SQL... I had in mind his "A Guide to the SQL Standard". I think the mildest thing he has ever said is "it has to be said that the SQL standard is not a particularly _good_ one". Next mildest: "SQL in its present form is extremely _un_orthogonal and is chock full of apparently arbitrary restrictions, exceptions, and special rules." And the relevant quote is in the Guide, which I haven't here, so from memory "There are a lot of principles known for designing programming languages. Unfortunately the design of SQL respects none of them." Of course the design principles he refers to: consistency, orthogonality, and so on are basically cognitive principles. In "Relational Database writings 1985-1989" chapter 13 is "EXISTS is not 'Exists'! (Some Logical Flaws in SQL)" whose abstract is (and I quote literally) "SQL is not sound." His point is that the logical connectives of SQL do not behave like the logical connectives of logic. (Neither do and-then and or-else in Prolog, but they are closer than SQL.) Again: this is a cognitive point; perhaps the operations in SQL can be justified, but can introducing such a clash between what the user expects (because of the names) and what the user _gets_ be justified? To return to Lisp: now that I have read part of CLtL-2, I have become convinced that Scheme is the Lisp for ->me<-. Why? Because I think I understand it, and I'm quite sure that I don't understand CLtL-2. -- Heuer's Law: Any feature is a bug unless it can be turned off.
jeff@aiai.ed.ac.uk (Jeff Dalton) (09/22/90)
In article <3781@goanna.cs.rmit.oz.au> ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) writes: >In article <3427@skye.ed.ac.uk>, jeff@aiai.ed.ac.uk (Jeff Dalton) writes: >> In article <3450@syma.sussex.ac.uk> aarons@syma.sussex.ac.uk (Aaron >> Sloman) writes: >> >It wasn't till I read this remark of Jeff's that I realised that one >> >reason I don't like Lisp is that, apart from "(" and ")", Lisp >> >doesn't help one to distinguish syntax words and function names. >> Actually, Pop-11 doesn't do much along those lines either. >> It's not like it uses a different font for them (cf Algol). >Come come. All that's needed for that is a suitable vgrind(1) description. >Surely there must be one available already; Pop-11 syntax is close enough >to Pascal/Modula syntax for it to work. Come come yourself. Haven't you ever seen that sort of thing done for Lisp? If not, check out _The Little Lisper_ sometime. >(I must admit that Interlisp-D's editors did a nice job of displaying >functions with "keywords" and comments very clearly distinguished.) That too. >I've been marking some 2nd year Pascal assignments recently, and have >come to the conclusion that Lisp programmers probably have _less_ trouble >with parentheses. Pascal's precedence rules are so counterintuitive that >people seem to throw in lots of parentheses just because they're never >quite sure what Pascal will do to them if they're left out. At least in >Lisp the rules are _simple_. Just so.
jeff@aiai.ed.ac.uk (Jeff Dalton) (09/25/90)
In article <3465@syma.sussex.ac.uk> aarons@syma.sussex.ac.uk (Aaron Sloman) writes: >jeff@aiai.ed.ac.uk (Jeff Dalton) (14 Sep 90 20:21:11 GMT) >commented on my remarks on the syntactic poverty of Lisp. >> One of the *mistakes* some people make when writing Lisp is to >> try to add the redundancy you describe by putting certain close >> parens on a line of their own followed by a comment such as >> " ; end cond". It makes the code *harder* to read, not easier. > >(He goes on to justify this by saying that indentation plus a good >editor helps, and that GOOD lisp programs have short procedure >definitions and that adding such comments makes them longer and >harder to take in.) Humm. After reading this message from you, and some e-mail, I've decided that I must not have been as clear as I thought, especially when I brought in the question of procedure length. What happens in Pop-11 is that every "if" ends in "endif", every "define" ends in "enddefine", and so on. I think that doing that (or something close to it) in Lisp is (a) unnecessary, and (b) a mistake. It makes the code harder to read, but not just, or even primarily, because it makes the code longer. The main problem is that the code is more cluttered, the indentation obscured, and it becomes harder to pick out more important names that appear in the code, because there are all these other things made out of letters. In the Lisp indentation style used in, for example, most of the good Lisp textbooks, close parens are not emphasised (they're just on the end of a line containing some code) and so don't get in the way when reading. They contribute to the overall "shape" of the code, but don't have to be processed individually by the (human) reader. If instead they're put on lines of their own, and especially if an "end" comment is attached, then they become more significant and it takes more work to precess them. Moreover, to the extent that one has to read the end marker, to see whether it's an "endif" or an "endfor", one has failed to see this scope information in the indentation itself; so I'm not sure the increase in redundancy is as much as one might think. Anyway, I don't know whether having distinct end brackets ("endif" vs "endfor") is better than what's done in Pascal (all such groupings use "begin" and "end" -- Pascal seems to have dropped the Algol 60 provision for comments following the "end") or C (all groupings use "{" and "}"). I just don't think it works that well in Lisp. But what about "long" procedures? One thing to note is that it isn't just a matter of the number of characters or lines involved. If we have a DEFUN, then a LET, and everything else is in a CASE, and each CASE clause is fairly short, the whole procedure can be fairly long without becoming especially hard to read. So it's really a question of complexity, in some sense. A good way to make long procedures more readable is to break them up, visually, into manageable sections. Blank lines and a brief comment introducing a section are more effective, in my experience, than emphasising end markers. Another important technique is to make the procedures shorter by using appropriate macros and higher-order functions (and, of course, by putting some things into separate procedures). In many languages, loops are written out using a "for" statement (or equivalent), and the programmer has to recognize certain common patterns of code. Lisp is often written that way too, but since it's fairly easy to write a function or macro that embodies the same pattern in a shorter, more easily recognized, form, the Lisp programmer has some effective alternatives to writing out loops in-line. Hence function such as MAPCAR, macros that implement "list comprehensions", and so on. >> Of course, it's no doubt possible to write procedures (such as ones >> that are too long) where end markers might make a difference. But >> is is also possible to avoid those cases, just as it is possible to >> avoid other bad practices. >I agree that a good editor helps a lot (though people often have to >read code without an editor, e.g. printed examples in text books, The editor is to help you *write* code that can be read. The whole point of good indentation is to make it possible to read the code without having to pay attention to individual parentheses. And the code is readable whether it's in a book, a file, or whatever. The reason people without a good Lisp editor may find end markers helpful is that they have difficulty matching parens when they're writing and find it difficult to check whether they've made a mistake. And, since they're new to Lisp, they may also find that syntax easier to read. But I certainly didn't mean to say (if I did say it) that a good editor was necessary in order to read the code. (Which is not to say there *couldn't* be an editor that helped.) >etc) and I agree that well-written short lisp definitions >(e.g. up to five or six lines) are often (though not always) easily >parsed by the human brain and don't need much explanatory clutter. I don't know where you got the "five or six lines" from; it's certainly not the limit I had in mind for "short". And *of course* such functions are not *always* easy to read; good indentation, and other good practices, are still necessary. There are readable Lisp procedure definitions up to a page long in some textbooks (and of course in other places). Once definitions are longer than a page, they are usually significantly harder to read in any language, although there are certain combinations of constructs for which long definitions aren't so great a problem. (Such the the CASE example mentioned above.) I don't think Lisp is necessarily much worse than other languages in this respect (if it's worse at all). >But I doubt that it is always desirable or possible to build good >programs out of definitions that are short enough to make the extra >contextual reminders unnecessary. Given your "five or six lines", I'm not surprised to find you think this way. And there are contextual reminders other than end markers, such as introductory comments, which I find more effective. >Even Common_Lisp_The_Language (second edition) has examples that I >think are long enough to benefit from these aids that you say are >unnecessary. (Scanning more or less at random for pages with lisp >code, I found examples on pages 340-349, 667, 759, 962 and 965. Or >are these just examples of bad lisp style? (I've seen much worse!) I have also seen code that is harder to read. Look at "AI Practice: Examples in Pop-11" sometime. [I'm sorry. I'm sure this book has many virtues. But some of the procedures cross a couple of page boundaries or are, in other ways, somewhat hard to read.] Moreover, we have to be clear on just what aids I think are unnecessary. I think the imitating Pop-11 end markers is not a good idea (because there are so many of them) but that end markers are sometimes helpful. This was discussed in more detail above. >My general point is that human perception of complex structures is >easiest and most reliable when there is well chosen redundancy in >the structures, and most difficult and error-prone when there isn't. >However, as you point out, too much redundancy can sometimes get in >the way, and we don't yet know the trade-offs. Here I agree. Well-chosen redundancy is important. However, it's important to bear in mind that many programmers new to Lisp haven't yet learned to "see" the redundancy or else chose programming styles that obscure it. The redundancy comes from three things: * Arity (eg CAR has one argument). * Indentation. * The overall shape of the parenthesis groups (note that this does not require that the reader pay much attention to individual parens) To show what I mean by the last, here's an example. Code that looks like this: ( (( ) ( )) (( ) ( )) ( ( ))) is usually a COND. (COND is perhaps the least readable Lisp construct.) Breaking up the paren groups tends to remove this information. Putting in end markers adds a different redundancy but tends to make the indentation less effective. Anyway, I'm not interested in a language war or in a discussion that more properly belongs in alt.religion.computers. I just want to keep some space for the view that Lisp is (or can be) readable and to suggest how some people may have been approaching the language in less effective ways. -- Jeff