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

I would like for a list to evaluate some terms but not others

0 views
Skip to first unread message

Jonathan Mark

unread,
Mar 10, 2008, 1:08:26 AM3/10/08
to
The following does not work

(define basepath ())
(set! basepath (1 . (0 . basepath)))

I get an error that 1 is not a procedure.

(define basepath ())
(set! basepath ('1 . (0 . basepath)))

produces the same error, that 1 is not a procedure.

However, if I say

(define basepath ())
(set! basepath '(1 . (0 . basepath)))

then I get the literal "basepath" inserted into my output, instead of
the value of basepath.

How can I get my list to avoid evaluating its first element, but still
get it to evaluate variable names?

How can I get Scheme to quote the first element of a list but

leppie

unread,
Mar 10, 2008, 1:49:13 AM3/10/08
to
"Jonathan Mark" <jonatha...@yahoo.com> wrote in message
news:027f1f3d-c1d5-4bf3...@d62g2000hsf.googlegroups.com...


The easiest is probably using quasiquote:

`(1 . (0 . ,basepath))


Jonathan Mark

unread,
Mar 10, 2008, 7:55:07 PM3/10/08
to
Thanks for telling me about quasiquote and unquote. It did exactly
what I wanted.

Pascal Bourguignon

unread,
Mar 16, 2008, 5:44:46 AM3/16/08
to
Jonathan Mark <jonatha...@yahoo.com> writes:

> Thanks for telling me about quasiquote and unquote. It did exactly
> what I wanted.

Indeed, but it's overkill for what you're doing.


Lists are built using the list function.
quote is used to prevent evaluation.

So instead of writing (quote (1 0 basepath))
and wondering why basepath is not evaluated, you should rather write:

(list (quote 1) (quote 0) basepath)

or

(list '1 '0 basepath)

or, in the case of numbers, since they're are self evaluating:

(list 1 0 basepath)


--
__Pascal Bourguignon__ http://www.informatimago.com/

WARNING: This product warps space and time in its vicinity.

Jonathan Mark

unread,
Mar 16, 2008, 3:44:41 PM3/16/08
to
The list function retains basepath as a separate list, so that if
basepath = (2 3) then (list 1 basepath) produces (1 (2 3)) .

I want to flatten the result to (1 2 3) and that is why I need to use
quasiquote.

Barry Margolin

unread,
Mar 16, 2008, 4:04:18 PM3/16/08
to
In article
<25876844-4368-408f...@e39g2000hsf.googlegroups.com>,
Jonathan Mark <jonatha...@yahoo.com> wrote:

What does (cons 1 basepath) produce?

--
Barry Margolin, bar...@alum.mit.edu
Arlington, MA
*** PLEASE don't copy me on replies, I'll read them in the group ***

Jonathan Mark

unread,
Mar 16, 2008, 11:37:11 PM3/16/08
to
> What does (cons 1 basepath) produce?

It produces a flattened list.
(define basepath '(2
(cons 1 basebath) ==> (1 2 3)


But I did not accurately describe in the message above what I wanted
to do.

I actually wanted to add a 0 and a 1 to the start of a list. For some
reason I wanted to do it in a single command. So I wrote:

(set! basepath (quasiquote (0 . (1 . ,basepath))))

(display basepath) ==> (0 1 2 3) which is what I wanted.

Rob Warnock

unread,
Mar 17, 2008, 4:56:46 AM3/17/08
to
Jonathan Mark <jonatha...@yahoo.com> wrote:
+---------------

| > What does (cons 1 basepath) produce?
|
| It produces a flattened list.
...

| But I did not accurately describe in the message above what I wanted
| to do.
| I actually wanted to add a 0 and a 1 to the start of a list.
+---------------

That's what Barry's trying to help you with!

+---------------


| For some reason I wanted to do it in a single command.

+---------------

For *what* reason?!? "Just because" isn't a good way to design programs.

+---------------


| So I wrote:
| (set! basepath (quasiquote (0 . (1 . ,basepath))))

+---------------

I'll bet you that your Scheme implements that something like this
under the hood:

(set! basepath (cons 0 (cons 1 basepath)))

Why shouldn't you as well? [Hint: It's even shorter than what you wrote!]


-Rob

-----
Rob Warnock <rp...@rpw3.org>
627 26th Avenue <URL:http://rpw3.org/>
San Mateo, CA 94403 (650)572-2607

Jonathan Mark

unread,
Mar 17, 2008, 11:16:40 AM3/17/08
to

> (set! basepath (cons 0 (cons 1 basepath)))
>
> Why shouldn't you as well? [Hint: It's even shorter than what you wrote!]
>

You are right of course. I guess that is one reason for learning
Scheme, in order to get one to think recursively. Cons'ing a cons for
whatever reason didn't occur to me.

Pascal J. Bourguignon

unread,
Mar 17, 2008, 11:33:11 AM3/17/08
to
Jonathan Mark <jonatha...@yahoo.com> writes:

You could write a list* function that takes as its last argument, a
list to be prepended on.

(define (last list)
(cond ((null? list) list)
((null? (cdr list)) list)
(else (last (cdr list)))))

(define (butlast list)
;; transformation into an accumulator left to the reader.
(cond ((null? list) '())
((null? (cdr list)) '())
(else (cons (car list) (butlast (cdr list))))))

(define (list* . args)
(let ((last-arg (car (last args)))
(previous-args (butlast args)))
(append previous-args last-arg))) ; == (cons ... (cons ... (cons ... last-arg)))


(list* 1 2 (list 3 4 5)) --> (1 2 3 4 5)

--
__Pascal Bourguignon__

Abdulaziz Ghuloum

unread,
Mar 17, 2008, 12:08:02 PM3/17/08
to
Pascal J. Bourguignon wrote:
> Jonathan Mark <jonatha...@yahoo.com> writes:
>
>> The list function retains basepath as a separate list, so that if
>> basepath = (2 3) then (list 1 basepath) produces (1 (2 3)) .
>>
>> I want to flatten the result to (1 2 3) and that is why I need to use
>> quasiquote.
>
> You could write a list* function that takes as its last argument, a
> list to be prepended on.

Just in case you're not aware of it, your list* is now a standard
procedure with the name cons* in R6RS. cons* is ``many conses''.

Also, the implementation of list*/cons* should not require two
recursive helpers and does not traverse the list twice.

(define (cons* x . x*)
(let f ([x x] [x* x*])
(cond
[(null? x*) x]
[else (cons x (f (car x*) (cdr x*)))])))

Aziz,,,

Pascal J. Bourguignon

unread,
Mar 17, 2008, 12:54:21 PM3/17/08
to
Abdulaziz Ghuloum <aghu...@cee.ess.indiana.edu> writes:

> Pascal J. Bourguignon wrote:
>> Jonathan Mark <jonatha...@yahoo.com> writes:
>>
>>> The list function retains basepath as a separate list, so that if
>>> basepath = (2 3) then (list 1 basepath) produces (1 (2 3)) .
>>>
>>> I want to flatten the result to (1 2 3) and that is why I need to use
>>> quasiquote.
>> You could write a list* function that takes as its last argument, a
>> list to be prepended on.
>
> Just in case you're not aware of it, your list* is now a standard
> procedure with the name cons* in R6RS. cons* is ``many conses''.

Thanks, I wasn't aware. I'm still using good old R5RS.


> Also, the implementation of list*/cons* should not require two
> recursive helpers and does not traverse the list twice.

If I wanted an optimized version of list* I would just have used
Common Lisp. The sources of butlast and last were provided only for
pedagogical purposes (but indeed, not to teach optimization).


> (define (cons* x . x*)

> (let f ((x x) (x* x*))
> (cond
> ((null? x*) x)
> (else (cons x (f (car x*) (cdr x*)))))))

Well, you've reduced the constant on time complexity, but you're still
O(N) in (stack) space...

--
__Pascal Bourguignon__

Abdulaziz Ghuloum

unread,
Mar 17, 2008, 1:59:10 PM3/17/08
to
Pascal J. Bourguignon wrote:

> If I wanted an optimized version of list* I would just have used
> Common Lisp.

What's that supposed to mean?

leppie

unread,
Mar 17, 2008, 2:07:15 PM3/17/08
to
"Pascal J. Bourguignon" <p...@informatimago.com> wrote in message
news:7cd4ptp...@pbourguignon.anevia.com...

>
> Well, you've reduced the constant on time complexity, but you're still
> O(N) in (stack) space...
>
> --
> __Pascal Bourguignon__


How about:

(define-syntax list*
(syntax-rules ()
[(_ e ... t) (apply list e ... t)]))

for simplicity :p

Cheers

leppie


Kjetil S. Matheussen

unread,
Mar 17, 2008, 3:30:20 PM3/17/08
to
On Mon, 17 Mar 2008, Pascal J. Bourguignon wrote:

> Abdulaziz Ghuloum <aghu...@cee.ess.indiana.edu> writes:
>
> > Pascal J. Bourguignon wrote:
> >> Jonathan Mark <jonatha...@yahoo.com> writes:
> >>
> >>> The list function retains basepath as a separate list, so that if
> >>> basepath = (2 3) then (list 1 basepath) produces (1 (2 3)) .
> >>>
> >>> I want to flatten the result to (1 2 3) and that is why I need to use
> >>> quasiquote.
> >> You could write a list* function that takes as its last argument, a
> >> list to be prepended on.
> >
> > Just in case you're not aware of it, your list* is now a standard
> > procedure with the name cons* in R6RS. cons* is ``many conses''.
>
> Thanks, I wasn't aware. I'm still using good old R5RS.
>
>
> > Also, the implementation of list*/cons* should not require two
> > recursive helpers and does not traverse the list twice.
>
> If I wanted an optimized version of list* I would just have used
> Common Lisp. The sources of butlast and last were provided only for
> pedagogical purposes (but indeed, not to teach optimization).
>

I think the reason for Abdulaziz cons* implementation
was to show a shorter and simpler version, not a more
pedagogical (I wonder what you mean by that?) or
more optimized one.

Kjetil S. Matheussen

unread,
Mar 17, 2008, 3:34:01 PM3/17/08
to

Oh, and by the way. The simplest solution here is
to use quasiquotation, not write a new function (or macro):

`(1 2 ,@basepath)

Kjetil S. Matheussen

unread,
Mar 17, 2008, 3:52:27 PM3/17/08
to

Oh, sorry, I didn't read your post good enough. The inclusion
of butlast and last was the pedagogical purpose. Well,
even without butlast and last, I thought your version
was bloated and boring while Abdulaziz' was short and elegant.

Rob Warnock

unread,
Mar 17, 2008, 10:38:54 PM3/17/08
to
Abdulaziz Ghuloum <aghu...@cee.ess.indiana.edu> wrote:
+---------------
+---------------

Probably nothing sinister, just that LIST* is a standard builtin in
Common Lisp, and thus is likely to be optimized by the implementation:

> (describe 'list*)

LIST* is an external symbol in the COMMON-LISP package.
Function: #<Function LIST* {1021E149}>
Function arguments:
(arg &rest others)
Function documentation:
Returns a list of the arguments with last cons a dotted pair
Its declared argument types are:
(T &REST T)
Its result type is:
T
>

E.g., its implementation in CMUCL is suitably low-level & grubby ;-}
[from "cmucl-19c/src/code/list.lisp"]:

;;; List* is done the same as list, except that the last cons
;;; is made a dotted pair

(defun list* (arg &rest others)
"Returns a list of the arguments with last cons a dotted pair"
(cond ((atom others) arg)
((atom (cdr others)) (cons arg (car others)))
(t (do ((x others (cdr x)))
((null (cddr x)) (rplacd x (cadr x))))
(cons arg others))))

Abdulaziz Ghuloum

unread,
Mar 17, 2008, 10:49:36 PM3/17/08
to
Rob Warnock wrote:
> Abdulaziz Ghuloum <aghu...@cee.ess.indiana.edu> wrote:
> +---------------
> | Pascal J. Bourguignon wrote:
> | > If I wanted an optimized version of list* I would just have used
> | > Common Lisp.
> |
> | What's that supposed to mean?
> +---------------
>
> Probably nothing sinister, just that LIST* is a standard builtin in
> Common Lisp, and thus is likely to be optimized by the implementation:

But I just said that cons* is also a standard built-in in R6RS Scheme.
So, it's just as likely to be optimized by Scheme implementations as
list* be optimized by Common Lisp implementations. Right?

Pascal J. Bourguignon

unread,
Mar 18, 2008, 11:38:59 AM3/18/08
to
Abdulaziz Ghuloum <aghu...@cee.ess.indiana.edu> writes:

Right. Common Lisp: 1984
R6RS: 2006

--
__Pascal Bourguignon__

Pascal J. Bourguignon

unread,
Mar 18, 2008, 12:54:42 PM3/18/08
to

Well, this is a philosophical aspect of programming.

Of course, you can implement list*/cons* as a stand alone nice little
function. But then, when you have another function to write, you're
left to the same bare foundation. Or in the process of writting
list*/cons*, you define "utility" functions, that allow you to
implement your first function more easily, and that allow you to
implement the following functions also more easily. Not only I do the
job, but I prepare for the next job, making it easier to do.


I don't think Abdulaziz's cons* was shorter than my list*:

(define (list* . args)
(let ((last-arg (car (last args)))
(previous-args (butlast args)))
(append previous-args last-arg)))

Basically; one function application, the let is here only as a comment
about the two sub-expressions:

(define (list* . args)
(append (butlast args) (car (last args))))

(define (cons* x . x*)
(let f ([x x] [x* x*])
(cond
[(null? x*) x]
[else (cons x (f (car x*) (cdr x*)))])))

A complex recursive loop, with TWO loop variables, and a condition.
You cannot deny it's more complex than append.


You could setup a psychological experiment to confirm it, or infirm
it, but I think mine was simplier to understand.

--
__Pascal Bourguignon__

Jens Axel Soegaard

unread,
Mar 18, 2008, 1:08:44 PM3/18/08
to
Pascal J. Bourguignon wrote:

> I don't think Abdulaziz's cons* was shorter than my list*:
>
> (define (list* . args)
> (let ((last-arg (car (last args)))
> (previous-args (butlast args)))
> (append previous-args last-arg)))
>
> Basically; one function application, the let is here only as a comment
> about the two sub-expressions:
>
> (define (list* . args)
> (append (butlast args) (car (last args))))

How about this one?

(define (list* . args)
(apply apply list args))

--
Jens Axel Søgaard

andreu...@yahoo.com

unread,
Mar 18, 2008, 2:34:36 PM3/18/08
to
On Mar 18, 11:54 am, p...@informatimago.com (Pascal J. Bourguignon)
wrote:


> I don't think Abdulaziz's cons* was shorter than my list*:
>

> (define (cons* x . x*)
> (let f ([x x] [x* x*])
> (cond
> [(null? x*) x]
> [else (cons x (f (car x*) (cdr x*)))])))
>
> A complex recursive loop, with TWO loop variables, and a condition.
> You cannot deny it's more complex than append.

On the contrary, it is a very simple self-contained recursive
specification of cons*.

> You could setup a psychological experiment to confirm it, or infirm
> it, but I think mine was simplier to understand.
>

> (define (list* . args)
> (append (butlast args) (car (last args))))

Be that as it may, your solution does not raise the expected arity
error if there is not at least one argument. If you had written out
the case-by-case specification as in Aziz's solution, you would
probably
not have made that mistake. Also, Aziz'z solution traverses the
argument list once, whereas you unnecessarily traverse it three
times.
I would consider that bad pedagogy.

Andre

Abdulaziz Ghuloum

unread,
Mar 18, 2008, 6:23:27 PM3/18/08
to

Oh, right. Because, like, optimizing cons* requires 22 years of
research, so, an optimized version of cons* is estimated to arrive
to Scheme in 2028. Sorry, missed that.

Pascal J. Bourguignon

unread,
Mar 19, 2008, 4:45:19 AM3/19/08
to

Very good, but perhaps a little too concise for the pedagogical
purpose of explicitely and clearly indicate what list* is.

--
__Pascal Bourguignon__

0 new messages