what's wrong with the use of apply append

Started by lyl, September 02, 2019, 11:26:41 PM

Previous topic - Next topic

lyl

First example:
(setq var "b")
(apply append '("a" var)) ;; I believe the result will be "ab", but what I get is error message.


Second example:
(setq var "b")
(append "a" var);; -> "ab"


I think the two examples are equivalent, but it seems not. Why? And why the first example is a wrong way to use "append" and how to make "apply append" work?

rickyboy

#1
What we were missing was the error message:


> (setq var "b")
"b"
> (apply append '("a" var)) ;; I believe the result will be "ab", but what I get is error message.

ERR: string expected in function append : 'var

The problem is that in the expression '("a" var), var is getting quoted; so, you end up passing a symbol as the second argument to append and hence it complains (in the error message) that var (a symbol) is not something that it can do anything with.



(The subtle thing to notice at the end of the error message is the single quote character right before "var".)



Another way, the expression '("a" var) is a list of a string and a symbol:


> '("a" var)
("a" var)
> (list '"a" 'var)
("a" var)

So, by substitution, these are equivalent:


> (apply append '("a" var))

ERR: string expected in function append : 'var
> (apply append (list '"a" 'var))

ERR: string expected in function append : 'var

On the other hand, in the case of the expression (append "a" var), the evaluator gets a chance to evaluate var (an unquoted symbol) to its current runtime value ("b").



So, to answer your last question, something like this would work:


> (apply append (list "a" var))
"ab"

Hope that helps.
(λx. x x) (λx. x x)

lyl

#2
Thank you so much for this detail explaination.

As you say, "so, you end up passing a symbol as the second argument to append".

The symbol 'var which is passed to "append" has been binded to "b", why is the evaluator not able to see it?

Dose that mean each element of a list which will be passed to a function by "apply" must be evaluated first? And is this a mechanism from "lisp" or from "newlisp"?

rickyboy

#3
QuoteThe symbol 'var which is passed to "append" has been binded to "b", why is the evaluator not able to see it?

The short answer is: because the quote prevents it from getting evaluated, as in:


> (setq var "b")
"b"
> 'var
var
> var
"b"

Here, the single quote character (preceding var) prevents var from being evaluated (to its current value).  Actually the expression 'var is shorthand for (quote var) and that *does* get evaluated -- it's just that the newLISP evaluator has a special rule for quote expressions: don't evaluate quote's argument, just return it exactly as it was given.


> (quote var)
var

The newLISP evaluator is exposed to the user via the primitive eval; so, one could evaluate the above quote expression "manually" (although in general, it's not considered good practice).


> (eval (quote var))
"b"

QuoteAnd is this a mechanism from "lisp" or from "newlisp"?

All the lisps that I know of have this same behavior.  For example, take a Scheme:


$ guile
guile> (define val "b")
guile> 'val
val
guile> (quote val)
val
guile> val
"b"
guile> (string-append "a" val)
"ab"
guile> (apply string-append '("a" val))

Backtrace:
In standard input:
   6: 0* [apply #<primitive-procedure string-append> ("a" {val})]
In unknown file:
   ?: 1  [string-append]
   ?: 2* [string-append "a" {val}]

ERROR: In procedure string-append:
ERROR: Wrong type (expecting string): val
ABORT: (wrong-type-arg)

guile> (apply string-append (list "a" val))
"ab"

Emacs Lisp:


*** Welcome to IELM ***  Type (describe-mode) for help.
ELISP> (setq val "b")
"b"
ELISP> 'val
val
ELISP> (quote val)
val
ELISP> val
"b"
ELISP> (concat "a" val)
"ab"
ELISP> (apply #'concat '("a" val))
*** Eval error ***  Wrong type argument: sequencep, val
ELISP> (apply #'concat (list "a" val))
"ab"
(λx. x x) (λx. x x)

lyl

#4
Oh, I understand it! @rickyboy And learn a lot from you. I will use "apply" more carefully.