Experience of Learning Lisp

Discussion of Common Lisp
Paul Donnelly
Posts: 148
Joined: Wed Jul 30, 2008 11:26 pm

Re: Experience of Learning Lisp

Post by Paul Donnelly » Sat Jul 18, 2009 3:48 pm

tayssir wrote:

Code: Select all

CL-USER> (listp (cons 1 2))
T

CL-USER> (list-length (cons 1 2))
; Evaluation aborted.
; The value 2 is not of type LIST.
;    [Condition of type TYPE-ERROR]
What's inconsistent about not being able to take the length of improper lists? I don't even know why a person would try to do this intentionally, since there would be no way of guessing how the standard defined their length short of looking it up.

And of course Common Lisp doesn't error on (cons 1 2). Representing pairs is a perfectly valid use for cons cells. Not that some other functions aren't dismayingly inconsistent, but I don't see how either cons or list-length is strange.

Paul
Posts: 106
Joined: Tue Jun 02, 2009 6:00 am

Re: Experience of Learning Lisp

Post by Paul » Sat Jul 18, 2009 6:36 pm

tayssir wrote:
Like what? The only thing that bugs me is (file-position s n) instead of (setf (file-position s) n)
Take a look at:

Code: Select all

(cons    collection item)
(gethash item       collection)
(elt     collection item)
(nth     item       collection)
(aref    collection items)
(assoc   items      collection)
(getf    collection item)
Other than your use of CONS to build a list along the CARs, I don't see the problem. The only functions in your list that could sensibly go either way are GETHASH and GETF, but it makes sense that they're the way they are—GETHASH is consistent with ASSOC; GETF follows GET for obvious reasons (which made sense at the time; less so now)

Paul
Posts: 106
Joined: Tue Jun 02, 2009 6:00 am

Re: Experience of Learning Lisp

Post by Paul » Sat Jul 18, 2009 6:43 pm

tayssir wrote:(Incidentally Clojure doesn't exhibit this particular behavior; (cons 1 2) throws an error, as the documentation clearly defines the 2nd parameter to be a seq.)
:roll:

Another reason to avoid Clojure.

Paul
Posts: 106
Joined: Tue Jun 02, 2009 6:00 am

Re: Experience of Learning Lisp

Post by Paul » Sat Jul 18, 2009 6:45 pm

tayssir wrote:But I fear we have blundered onto yet another lisp inconsistency, far more insidious than even the preceding ones. How do people frequently construct an alist?

Code: Select all

CL-USER> (defvar *foo*
           '((:a . 1)
             (:b . 2)))

;; “I just sensed a glitch in the Matrix.”
...
It's undefined to destructively modify "literals" like quoted lists.
Judging by the prompt in front, your "literal" was defined at the REPL, so it's perfectly well defined, but in any case, how would that be "an inconsistency"?

gugamilare
Posts: 406
Joined: Sat Mar 07, 2009 6:17 pm
Location: Brazil
Contact:

Re: Experience of Learning Lisp

Post by gugamilare » Sat Jul 18, 2009 7:01 pm

tayssir wrote:

Code: Select all

CL-USER> (defvar *foo*
           '((:a . 1)
             (:b . 2)))

;; “I just sensed a glitch in the Matrix.”
Ok, so they're playing with this table, and soon attempt to set the value of one of the keys via a destructive operation like (setf (cdr ...)). Like in the Hyperspec.
Hum... That really sucks...

I believe this is user's mistake, not implementation's nor CL's one. This is constant data, and modifying constant data would be an error in any language (other than Clojure, you might say, and perhaps a few other languages which use non-destructive data, but that is a Clojure's feature, not CL's defect).

In any case, thanks for the advice, I'll remember to always use copy-tree when I create alists like this one.

skypher
Posts: 34
Joined: Thu Jul 03, 2008 6:12 am

Re: Experience of Learning Lisp

Post by skypher » Sun Jul 19, 2009 12:29 am

gugamilare wrote:In any case, thanks for the advice, I'll remember to always use copy-tree when I create alists like this one.
Or even better just build your list with LIST unless you can guarantee that it won't be modified by you or someone else using that list.

lnostdal
Posts: 20
Joined: Thu Jul 03, 2008 2:01 pm
Location: Skien, Norway
Contact:

Re: Experience of Learning Lisp

Post by lnostdal » Sun Jul 19, 2009 3:42 am

tayssir wrote:

Code: Select all

CL-USER> (defvar *foo*
           '((:a . 1)
             (:b . 2)))
Please, this is well known stuff for most programmers and if not it is an useful feature to be (made) aware of. Literal data, constants and SBCL's global variables (SB-EXT:DEFGLOBAL) are important when things need to execute as fast as possible.

Always-bound globals that cannot (by user's wish; they specify intention) be locally bound are of interest for their semantics also; not just performance.

edit:
Just in case, before getting hit with "you shouldn't optimize prematurely" or similar -- you should know that there are people out there who deal with other problems and things than you do. These people very much welcome the fact that CL is multi-paradigm and has a core language for them to build on with almost no indirection in it by default.

tayssir
Posts: 35
Joined: Tue Jul 15, 2008 2:33 pm

Re: Experience of Learning Lisp

Post by tayssir » Sun Jul 19, 2009 6:45 am

Before I spend more of my time answering further, no one responded to this claim:
Paul wrote:
tayssir wrote:

Code: Select all

CL-USER> (defvar *foo*
           '((:a . 1)
             (:b . 2)))
Ok, so they're playing with this table, and soon attempt to set the value of one of the keys via a destructive operation like (setf (cdr ...)). Like in the Hyperspec.

Oops.
Judging by the prompt in front, your "literal" was defined at the REPL, so it's perfectly well defined, but in any case, how would that be "an inconsistency"?
What do people think: is this refutation correct or not? If the DEFVAR was executed at the repl, is the subsequent destructive operation no longer undefined by the spec? (To start you off, here is this hyperspec entry.)

Paul
Posts: 106
Joined: Tue Jun 02, 2009 6:00 am

Re: Experience of Learning Lisp

Post by Paul » Sun Jul 19, 2009 7:01 pm

tayssir wrote:Before I spend more of my time answering further, no one responded to this claim:
Paul wrote:
tayssir wrote:

Code: Select all

CL-USER> (defvar *foo*
           '((:a . 1)
             (:b . 2)))
Ok, so they're playing with this table, and soon attempt to set the value of one of the keys via a destructive operation like (setf (cdr ...)). Like in the Hyperspec.

Oops.
Judging by the prompt in front, your "literal" was defined at the REPL, so it's perfectly well defined, but in any case, how would that be "an inconsistency"?
What do people think: is this refutation correct or not? If the DEFVAR was executed at the repl, is the subsequent destructive operation no longer undefined by the spec? (To start you off, here is this hyperspec entry.)
The reader must generate a new list when it reads the form in, and QUOTE just returns the identical list that is its argument, therefore it returns the fresh list constructed by the reader; there's no way to tell the difference between that list and one constructed with LIST, therefore there's no way mutating it can have any different effect than if you had used LIST. So either all list mutations are undefined, or this one isn't (or Lisp is magical).

The spec is allowing for the possibility of similar lists being merged when externalized in a FASL file, etc.

gugamilare
Posts: 406
Joined: Sat Mar 07, 2009 6:17 pm
Location: Brazil
Contact:

Re: Experience of Learning Lisp

Post by gugamilare » Sun Jul 19, 2009 8:29 pm

Paul wrote:The reader must generate a new list when it reads the form in, and QUOTE just returns the identical list that is its argument, therefore it returns the fresh list constructed by the reader; there's no way to tell the difference between that list and one constructed with LIST, therefore there's no way mutating it can have any different effect than if you had used LIST. So either all list mutations are undefined, or this one isn't (or Lisp is magical).

The spec is allowing for the possibility of similar lists being merged when externalized in a FASL file, etc.
The problem is that modifying literal data may break something. This example is classic:

Code: Select all

(defun foo ()
  '(1 2 3))

(setf (car (foo)) 10)

(foo) => (10 2 3)
Anyway, in the given example, I don't know any way to break that code, but the same example using a local variable inside a function, for instance, will break the code (I once saw a friend of mine struggling to find where was the bug in his function because of this, and I explained to him that he couldn't modify constant data since it is allocated only once during compilation or load time).

Post Reply