From: ··········@gmail.com
Subject: Unexpected type errors inside loops
Date: 
Message-ID: <1118679018.017914.123830@o13g2000cwo.googlegroups.com>
I'm a lisp newbie, and not all that experienced with programming in
general. While practicing writing macros, I encountered a type-error
when trying to perform arithmatic on a variable set by a looping
construct when the variable is set to an expression that returns a
number. For example:

(dolist (x '(1 2 (+ 1 2))) (+ 1 x)) ;type error

This is not what I expected, since (+ 1 (+ 1 2)) is perfectly valid,
and (let ((x (+ 1 2))) (+ 1 x)) works as well. I have the same problem
using loop instead of dolist. I thought that the problem might be that
x doesn't get evaluated because dolist and loop are macros, so I wrote
a simple macro to test this:

(defmacro add-one (x)
  `(+ 1 ,x))

(add-one (+ 1 2)) ;evaluates to 4

I searched for information about type errors inside loops, but I didn't
find anything applicable to this situation. I can think of workarounds
to get the desired behavior on my own. What I'm interested in is why
this happens.

From: Eric Lavigne
Subject: Re: Unexpected type errors inside loops
Date: 
Message-ID: <1118679646.481741.291980@z14g2000cwz.googlegroups.com>
>(dolist (x '(1 2 (+ 1 2))) (+ 1 x)) ;type error

>(defmacro add-one (x)
>  `(+ 1 ,x))
>(add-one (+ 1 2)) ;evaluates to 4

The big difference here, is that in the second case you use backquote
and comma. The purpose of comma is to allow part of the quoted
expression to be evaluated. Comma only works if the expression is
quoted with backquote. So try this:
(dolist (x `(1 2 ,(+ 1 2))) (+ 1 x))
From: Zach Beane
Subject: Re: Unexpected type errors inside loops
Date: 
Message-ID: <m3slzm2pc7.fsf@unnamed.xach.com>
··········@gmail.com writes:

> (dolist (x '(1 2 (+ 1 2))) (+ 1 x)) ;type error

Not every item in '(1 2 (+ 1 2)) is a number that can be used with +;
the third thing is a list.

Zach
From: ··········@gmail.com
Subject: Re: Unexpected type errors inside loops
Date: 
Message-ID: <1118682857.673139.287570@g44g2000cwa.googlegroups.com>
Thanks, everyone. Eric, that significantly added to my understanding.
Peter, I'm currently working my way through your book; it's the first
one I've seen that does a good job teaching the reader to think in lisp
early on. Despite your best efforts, I somehow missed the fact that '(1
2 (+ 1 2)) isn't the same as (list (1 2 (+ 1 2)))

In situations where I'm dealing with a list that might be quoted, is it
reasonable to deal with it like this?

(dolist (y lst)
  (let ((x (eval y)))
    (do-something-with x)))
From: Eric Lavigne
Subject: Re: Unexpected type errors inside loops
Date: 
Message-ID: <1118686923.900392.206360@g47g2000cwa.googlegroups.com>
>In situations where I'm dealing with a list that might be quoted, is it
>reasonable to deal with it like this?

>(dolist (y lst)
>  (let ((x (eval y)))
>    (do-something-with x)))

This works, but you should ask yourself why you don't know whether it
is quoted. Is this part of a function which takes x as an argument...
and someone passed '(+ 1 2) instead of 3? In that case, why did they
choose to quote it? The rule of thumb is: don't use eval. Like any rule
of thumb, you can ignore it when you really need to, for example if you
are writing an interpreter with an REPL (read-eval-print-loop).
From: ··········@gmail.com
Subject: Re: Unexpected type errors inside loops
Date: 
Message-ID: <1118694188.254430.305360@g49g2000cwa.googlegroups.com>
This is all mostly theoretical; stuff I'm writing to learn about how
lisp works.

Eric Lavigne wrote:
> This works, but you should ask yourself why you don't know whether it
> is quoted.

In practice, if I was writing a function that takes a list and does
math with the elements, it seems like it would be more robust, or at
least more flexible to have it evaluate the elements first. For
example, I don't know if it's quoted because I wrote a library and
other people are using it. I could test to see if it's quoted, but it
seemed easier to just eval it.

>The rule of thumb is: don't use eval.

I'm sure I'm showing my ignorance here, but why?
From: Eric Lavigne
Subject: Re: Unexpected type errors inside loops
Date: 
Message-ID: <1118704170.243820.248550@g49g2000cwa.googlegroups.com>
>For example, I don't know if it's quoted because I wrote a library and
>other people are using it. I could test to see if it's quoted, but it
>seemed easier to just eval it.

If you wrote a function that performs calculations on members of a
list, you should expect a list of numbers to be passed to it. If
someone misused it by passing you a letter, would you convert the
letter to its ascii value and continue the calculation? Or is it better
for your function to crash and make it obvious that they did something
wrong? Likewise, there is no reason that someone would pass you a list
containing quoted math operations, and it is better to just let the
error happen in this case.

>>The rule of thumb is: don't use eval.
>I'm sure I'm showing my ignorance here, but why?

Paul Graham's ANSI Common Lisp, p161:

Calling eval is one way to cross the line between lists and code.
However, it is not a very good way:

1) It's inefficient: eval is handed a raw list, and either has to
compile it on the spot, or evaluate it in an interpreter. Either way is
much slower than running compiled code.

2) The expression is evaluated with no lexical context. If you call
eval within a let, for example, the expressions passed to eval cannot
refer to variables established by the let.

There are much better ways (described in the next section) to take
advantage of the possibility of generating code. Indeed, one of the
only places where it is legitimate to use eval is in something like a
toplevel loop.
From: Ivan Boldyrev
Subject: Re: Unexpected type errors inside loops
Date: 
Message-ID: <ps33o2-53s.ln1@ibhome.cgitftp.uiggm.nsc.ru>
On 9140 day of my life Eric Lavigne wrote:
> Calling eval is one way to cross the line between lists and code.
> However, it is not a very good way:

Technically, COERCE is another:

> (coerce '(lambda (x) (+ x x x)) 'function)

Though, problems are same.  But if you use something like

> (compile nil (coerce '(lambda (x) bla-bla-bla) 'function))

you may get quite efficient code.  If BLA-BLA-BLA is code optimized
for current data, you may outperform C... ;)

-- 
Ivan Boldyrev

                                                  Is 'morning' a gerund?
From: Tayssir John Gabbour
Subject: Re: Unexpected type errors inside loops
Date: 
Message-ID: <1118725673.522247.182500@g43g2000cwa.googlegroups.com>
··········@gmail.com wrote:
> Eric Lavigne wrote:
> >The rule of thumb is: don't use eval.
>
> I'm sure I'm showing my ignorance here, but why?

People have already mentioned that eval in Common Lisp evaluates things
in the "null lexical environment."
http://www.lisp.org/HyperSpec/Body/fun_eval.html

(Presumably this is due to the common compiler optimization of getting
rid of variable names, so after compilation, eval won't know what some
lexical variable FOO is referring to.)

If you want to keep lexical environments, there's lambda. Used with
apply/funcall.

Eval can be useful, of course. And I'm sure one can conceive of a
language where eval is more obviously useful than in CL. (I hear "Pico
Lisp" is one.)


> This is all mostly theoretical; stuff I'm writing to learn about how
> lisp works.
>
> Eric Lavigne wrote:
> > This works, but you should ask yourself why you don't know whether it
> > is quoted.
>
> In practice, if I was writing a function that takes a list and does
> math with the elements, it seems like it would be more robust, or at
> least more flexible to have it evaluate the elements first. For
> example, I don't know if it's quoted because I wrote a library and
> other people are using it. I could test to see if it's quoted, but it
> seemed easier to just eval it.

Well, quote is used to ensure something isn't to be evaluated. So you'd
be evaluating something that presumably isn't supposed to be. ;)

Plus, when you're writing a function, there's usually some sort of
contract at work, so users aren't passing insane arguments to it. So
you don't have to deal with every little possibility. Statically- and
optionally-typed languages try making this contract explicit; many
unfriendly ones even refuse to compile/run your program unless it knows
for a fact these contracts are upheld.

If you want to read more about this stuff in a "theoretical" light,
take a look at:
http://lisp.tech.coop/AudioVideo#sicp
I'm not a big fan of SICP's puritanism, but it's pretty popular.


Tayssir
From: Pascal Bourguignon
Subject: Re: Unexpected type errors inside loops
Date: 
Message-ID: <873brmvscw.fsf@thalassa.informatimago.com>
··········@gmail.com writes:
>>The rule of thumb is: don't use eval.
>
> I'm sure I'm showing my ignorance here, but why?

Because EVAL evaluates in the global environement, and won't be doing
what you think.

(let ((x 1)) (eval '(* x 2))) --> *** - EVAL: variable X has no value


-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
You're always typing.
Well, let's see you ignore my
sitting on your hands.
From: Wade Humeniuk
Subject: Re: Unexpected type errors inside loops
Date: 
Message-ID: <oapre.62744$tt5.35799@edtnps90>
Pascal Bourguignon wrote:
> ··········@gmail.com writes:
> 
>>>The rule of thumb is: don't use eval.
>>
>>I'm sure I'm showing my ignorance here, but why?
> 
> 
> Because EVAL evaluates in the global environement, and won't be doing
> what you think.
> 
> (let ((x 1)) (eval '(* x 2))) --> *** - EVAL: variable X has no value
> 
> 

That's not really fair, as...

CL-USER 1 > (eval '(let ((x 1)) (* x 2)))
2

 From my point of view, there is really no reason not to use eval.  Go ahead,
but I never use it unless I have too, which is very rare.  (It is there
and it is part of the original McCarthy's Lisp Paper). Your coding example can
be easily fixed without resorting to EVAL.  I suppose you can see
it as a law of coding "Do not use a sledge-hammer when a feather will do."

There is part of me that thinks by making "mistakes", like using EVAL in this
case might lead to new understandings about Lisp (since it is such a fundamental
concept).  There is nothing like naive use to see things in a new way.

See,

http://lib.store.yahoo.com/lib/paulgraham/jmc.lisp

Wade
From: Eric Lavigne
Subject: Re: Unexpected type errors inside loops
Date: 
Message-ID: <1118707967.483437.194010@g44g2000cwa.googlegroups.com>
> I suppose you can see it as a law of coding
> "Do not use a sledge-hammer when a feather will do."

Corollary: "Do not use Lisp when FORTRAN will do."

I am guilty of breaking this law ^^
From: M Jared Finder
Subject: Re: Unexpected type errors inside loops
Date: 
Message-ID: <J7adnc5EbYYwwTPfRVn-2w@speakeasy.net>
Zach Beane wrote:
> ··········@gmail.com writes:
> 
> 
>>(dolist (x '(1 2 (+ 1 2))) (+ 1 x)) ;type error
> 
> 
> Not every item in '(1 2 (+ 1 2)) is a number that can be used with +;
> the third thing is a list.

Just to be pedantic (which is helpful for learning), '(1 2 (+ 1 2)) is 
not a list we care about.  What we care about is the list it evaluates 
to, which is printed as (1 2 (+ 1 2)), i.e., the list containing the 
number 1, the number 2, and a list containing the symbol +, the number 
1, and the number 2.

   -- MJF
From: Peter Seibel
Subject: Re: Unexpected type errors inside loops
Date: 
Message-ID: <m2fyvmnrzj.fsf@gigamonkeys.com>
··········@gmail.com writes:

> I'm a lisp newbie, and not all that experienced with programming in
> general. While practicing writing macros, I encountered a type-error
> when trying to perform arithmatic on a variable set by a looping
> construct when the variable is set to an expression that returns a
> number. For example:
>
> (dolist (x '(1 2 (+ 1 2))) (+ 1 x)) ;type error
>
> This is not what I expected, since (+ 1 (+ 1 2)) is perfectly valid,
> and (let ((x (+ 1 2))) (+ 1 x)) works as well.

You need to look up what ' (a.k.a. QUOTE) does. Or just try this:

  (dolist (x '(1 2 (+ 1 2))) (print x))

And for comparison:

  (dolist (x (list 1 2 (+ 1 2))) (print x))

Now cue Kenny Tilton's rant about how Lisp book authors tend to lazily
use QUOTE to construct literal lists in situations where they can get
away with it and how that confuses their readers into thinking that
they can use in situations where they can't. FWIW, one book, whose
author I happen to know tried pretty hard to not be lazy in this way,
is available online at:

  <http://www.gigamonkeys.com/book/>

(If you like it, you can also buy it in a bookstore near you.)

-Peter

-- 
Peter Seibel           * ·····@gigamonkeys.com
Gigamonkeys Consulting * http://www.gigamonkeys.com/
Practical Common Lisp  * http://www.gigamonkeys.com/book/