Why does `(= (car x) 'z)` work? - syntax

I was stumbling through the Arc tutorial when I got sort of confused with this:
Quoted from the Arc Tutorial:
Like Common Lisp assignment, Arc's = is not just for variables, but
can reach inside structures. So you can use it to modify lists:
arc> x
(a b)
arc> (= (car x) 'z)
z
arc> x
(z b)
But lisp is executed recursively, right? It says that car returns the first value in a list. So:
arc> (car x)
a
which makes sense, but then why isn't (= (car x) 'z) equal to (= a 'z), which would result in:
arc> a
z
arc> x
(a b) ; Note how this hasn't changed
but it doesn't. Instead, it appears that (= (car x) 'z) seems to have the effects of (= x (list 'z (car (cdr x)))):
arc> (= x '(a b))
(a b)
arc> (= (car x) 'z)
z
arc> x
(z b)
...
arc> (= x '(a b))
(a b)
arc> (= x (list 'z (car (cdr x))))
(z b)
arc> x
(z b)
So why exactly does (= (car x) 'z) work that way and what is it that I'm missing here?
Note: this is my first introduction to LISP.

= is a special operator, it's not a function. So its arguments are not evaluated according to the normal recursive process. The first argument is treated specially, it identifies a place to assign to, not the value already in that place. It may have to evaluate subexpressions within it to find the place, but once it gets to the place, it stops evaluating. The second argument will be evaluated normally, to get the value to assign there.

= appears to be an assignment operator in Arc, the equivalent in Common Lisp would be setf. In this case, (car x) returns the place that is to be modified:
? (defparameter x '(a b))
X
? x
(A B)
? (setf (car x) 'z)
Z
? x
(Z B)
See also here.

= is a macro or rather "special operator", which is just a fancy name for built-in macro. Macros' arguments (unlike functions' arguments) aren't evaluated at all, so the = operator gets (car x) unevaluated ==> it get's the list (car x) itself! Now, that = operator contains miniature code walker that traverses the list (car x) and figures out what place would be read from if the list was evaluated. And assigns to that place.
What does it assign? The result of evaluating the second argument, it evaluates that one manually.
So the effective evaluation scheme for = is in fact
(= <unevaluated-argument> <evaluated-argument>)
EDIT:
Another example of macro or special operator is if. in (if <cond> <a> <b>), if starts being evaluated first and gets arguments <cond>, <a> and <b> raw - unevaluated. Then it manually evaluates <cond> and depending on the result, it either evaluates <a> or <b> and returns result of that. If everything was really evaluated recursively, you could never have working if or cond or loop or short-circuit and and or and so on...
NOTE: = is probably (= I suppose) a macro and not special operator, at least its equivalent setf in common lisp is a macro. I doubt that P. Graham embedded = directly into the compiler. But it's not really important to know.

If you have the book "ANSI Common Lisp", there is such sentence in chapter 3.3 Why Lisp Has No Pointers:
One of Secrets to understanding Lisp is to realize that variables have values in the same way that lists have elements. As conses have pointers to their elements, variables have pointers to their values.
If x is assigned a list:
arc> (= x '(a b))
(a b)
It formulates as such, the variable x points to a list. The 1st position of the list points to the symbol a and the 2nd points to the symbol b:
When car of x is assigned with 'z in (= (car x) 'z), simply the 1st position points the new symbol z.
Finally, in the expression (= a 'z), a variable a is assigned and thus points to the symbol z

Related

Function Definitions After Expressions in Scheme

I understand I can't define a function inside an expression, but I'm getting errors defining one after an expression within the same nested function. I'm using R5RS with DrScheme.
For example, this throws an error, 'define: not allowed in an expression context':
(define (cube x)
(if (= x 0) 0) ;just for example, no reason to do this
(define (square x) (* x x))
(* x (square x)))
In R5RS you can only use define in rather specific places: in particular you can use it at the beginning (only) of forms which have a <body>. This is described in 5.2.2. That means in particular that internal defines can never occur after any other expression, even in a <body>.
Native Racket (or whatever the right name is for what you get with#lang racket) is much more flexible in this regard: what you are trying to do would (apart from the single-armed if) be legal in Racket.
You can use define inside another definition. Some Schemes won't allow you to have an if without the else part, though. This works for me:
(define (cube x)
(if (= x 0) 0 1) ; just for example, no reason to do this
(define (square x) (* x x))
(* x (square x)))
Have you tried making the definition at the beginning? maybe that could be a problem with your interpreter.
define inside a procedure body (that includes all forms that are syntactic sugar for procedures, like let, let*, and letrec) are only legal before other expressions and never after the first expression and it can not be the last form.
Your example shows no real reason for why you would want to have an expression before definitions. There is no way you can get anything more than moving all define up to the beginning. eg.
(define (cube x)
;; define moved to top
(define (square x) (* x x))
;; dead code moved under define and added missing alternative
(if (= x 0) 0 'undefined)
(* x (square x)))
If the code isn't dead. eg. it's the tail expression you can use let to make a new body:
(define (cube x)
(if (= x 0)
0
(let ()
;; this is top level in the let
(define (square x) (* x x))
;; required expression
(* x (square x)))))
I think perhaps we would need an example where you think it would be warranted to have the define after the expression and we'll be happy to show how to scheme it up.

What causes an unbound variable error in Scheme?

I've started out with SICP and I'm new to Scheme. I've tried debugging this piece of code and even compared it to similar solutions.
(def (myFunc x y z)
(cond ((and (<= x y) (<= x z)) (+ (* y y) (* z z)))
((and (<= y x) (<= y z)) (+ (* x x) (* z z)))
(else (+ (* x x) (* y y)))))
This function returns the sum of the squares of two largest numbers.
When I run this, the interpreter gives out ";Unbound variable: y". Could you please explain the cause behind this error?
Help is greatly appreciated :)
The function-defining primitive in Scheme is called define, not def.
As it is, the whole (def ...) expression was treated as a function call to def. So its arguments' values needed to be found. The first argument (myFunc x y z) is a function call so its argument values needed to be found. Apparently your implementation wanted to find out the value of y first.
The R5RS standard says "The operator and operand expressions are evaluated (in an unspecified order) and the resulting procedure is passed the resulting arguments."
It is likely your implementation chooses the rightmost argument first, which leads to (<= x y) being evaluated first (because of special rules of evaluating the cond and and special forms), with y in its rightmost position.

How do I use and/or instead of if/cond?

I'm new to Scheme programming and I've gotten this task that I just can't find out how to work correctly. I'm supposed to define a procedure with one parameter (a number). If the number is positive I want 1 to be returned, -1 if the number is negative and 0 if it is 0, using only and/or. If and cond is not allowed. I only get #t or #f returned, but you see that's not what I want. Any help or pointers is appreciated
You can solve your problem if you look at the following equivalence, valid when every expj has a value different from #f:
(cond (test1 exp1) (or (and test1 exp1)
(test2 exp2) (and test2 exp2)
... ≡ ...
(testn expn) (and testn expn)
(else expn+1)) expn+1)
Since the function that gets the sign of a number can simply be written in this way:
(define (sign x)
(cond ((> x 0) +1)
((< x 0) -1)
(else 0)))
after applying the above equivalence, since every result is an integer, different from #f, this function becomes equal to the solution proposed also in another answer:
(define (sign x)
(or (and (> x 0) +1)
(and (< x 0) -1)
0))
So, which is the reason of the above equivalence? It depends on the fact that and evaluates its arguments in turn; as soon as one of them is #f, it stops by returning #f, otherwise returns its last argument (and this explains the single branches (and testj expj)); while or evaluates its arguments in turn; as soon as one of them is not #f, it stops by returning it, otherwise returns its last argument (and this explains the chain (or (and ...) (and ...) ... expn+1)).
(define test
(lambda (n)
(or (and (< n 0) -1)
(and (= n 0) 0)
1)))
Part of the trick is understanding that and, if everything evaluates to true, will return the last item it evaluated, while or will return the first thing that successfully evaluates to true. The other part is realizing that everything except for #f is considered "true."
The transformation of and is seen in the report but to not include the actual macros it's basically this:
; only one argument
(and a) ; ===>
a
; one of more
(and a b ...) ; ==>
(if a
(and b ...)
#f)
All arguments must be evaluate to a positive value and the last value is the result, else #f. It short circuits so when something is #f the rest of the expressions are never evaluated.
For or is like this:
(or a) ; ==>
a
(or a b ...) ; ==>
(let ((a-value a))
(if a-value
a-value
(or b ...)))
The first argument that does not evaluate to #f gets returned. If all values are #f the last #f will be the result.
Thus if you want:
(if a b c) ; ==>
(let ((tmpa a))
(or (and atmpa b)
(and (not atmpa) c)) ; not part only important if b can be #f
I use let to prevent evaluating the same expression several times. eg. if you had one that printed something like (begin (display "hello") #f) or it's an expensive calculation then it's necessary or else you can just substitute the variable with the expression. eg. the last would become:
(or (and a b)
(and (not a) c))
That transformed back with no temporary variables become:
(if (if a b #f)
(if a b #f)
(if (not a) c #f))
If b is #f value, then the result is #f because of the last if. Thus everytime a is true b is the result. Everytime it's false, c is the answer. Thus
(if a b c)
So imagine you want to return the first true value in a list.
(define (first-true lst)
(and (not (null? lst))
(car lst)
(first-true (cdr lst))))

Compile/Evaluate operands in tailposition

I have a project for school for which I'm supposed to optimize a compiler/evaluator for Scheme.
The task is to implement tail-call optimization wherever possible.
I'm aware of the known tail-call optimization as shown below:
(define (f x)
<send some rockets into space>
(f (+ x 1)))
However, I'm thinking about evaluating operands in tail position as well. Suppose the following:
; The function
(define (f a b c)
<send some monkeys into space>
1)
; Call the function with (f 3 4 5)
(f (+ 1 2) (begin (define x 4) x) 5))
Evaluating the operands (+ 1 2), (begin (define x 4)) and 5 could be done in tail position, right?
Each of the operands are evaluated in their own environment. I tried this by using the regular R5RS in DrRacket with the following expression:
(+ (begin (define x 5) x) x)
If the operands would be evaluated in the same environment I would be able to pass the x defined in the first operand as the second operand. This is however not possible.
So, is it correct for me to assume that each operand can be evaluated in tail position?
"Tail position" is always relative to some outer expression. For example, consider this:
(define (norm . args)
(define (sum-of-squares sum args)
(if (null? args)
sum
(let ((arg (car args)))
(sum-of-squares (+ sum (* arg arg)) (cdr args)))))
(sqrt (sum-of-squares 0 args)))
The recursive call to sum-of-squares is indeed in tail position relative to sum-of-squares. But is it in tail position relative to norm? No, because the return value from sum-of-squares is sent to sqrt, not directly to norm's caller.
The key to analysing whether an expression A is in tail position relative to outer expression B, is to see whether A's return value is directly returned by B, without any further processing.
In your case, with your expression (f (+ 1 2) (begin (define x 4) x) 5) (which isn't actually valid, by the way: perhaps you meant (f (+ 1 2) (let () (define x 4) x) 5) instead), none of the subexpressions (+ 1 2), (let () (define x 4) x), and 5 are in tail position with respect to f, since their values have to be collected first, and then passed to f (which is a tail call).
None of the operands of an application (op1 op2 ...) is in tail position.
For R5RS Scheme you can see the position in which an application occurs in a tail context here:
https://groups.csail.mit.edu/mac/ftpdir/scheme-reports/r5rs-html.old/r5rs_22.html
So I finally figured it out.
In regular R6RS operands can never be evaluated in tail position because R6RS specifies that there is no strict order in which they are evaluated.
However, in this self-built evaluator for Scheme I do specify the order in which they are evaluated. Ergo, I can strictly define which operator is the last one, and that one can be evaluated in tail position.

Function for detecting quotes in Scheme code

I am trying to write a function that can check whether or not some input is a quotation for a syntax checker.
I have the following code:
(define is-quote-expression?
(lambda (v)
(equal? (car v) 'quote)
(is-quotation? (cdr v)))))
(define is-quotation?
(lambda (v)
(or (number? v)
(boolean? v)
(char? v)
(string? v)
(symbol? v)
(null? v)
(and (pair? v)
(is-quotation? (car v))
(is-quotation? (cdr v)))))
When I try to evaluate, I get the following:
(is-quote-expression? '1)
#f
(is-quote-expression? (cons 'quote 1))
#t
I think my TA told me that the Scheme environment replaced all "'" with "'quote", however, this does not seem to be the case. We are running Petite Chez Scheme.
What am I not seeing?
Thanks in advance.
There are a couple of problems with your code, for starters the (lambda (pair? v) part in is-quote-expression? is almost certainly a mistake (you're defining a lambda with two parameters called pair? and v).
Also, I believe you intended to call is-quotation? from is-quote-expression? only if v isn't a pair, so it doesn't make sense to ask again if (pair? v) in is-quotation?. And who said that a pair is a quotation only if both its car and cdr are quotations?
Here, I believe this is what you intended:
(define is-quote-expression?
(lambda (v)
(if (pair? v)
(equal? (car v) 'quote)
(is-quotation? v))))
(define is-quotation?
(lambda (v)
(or (number? v)
(boolean? v)
(char? v)
(string? v)
(symbol? v)
(null? v))))
I agree with Óscar's post, though, is-quote-expression? accepts a list rather than a pair and returns whether it was a quotation.
(define is-quote-expression?
(lambda (v)
(and (proper-list-of-given-length? v 2)
(equal? (car v) 'quote)
(is-quotation? (cadr v)))))
Also, your original question shows some confusion as to what quote actually does. This is what really should happen:
> (is-quote-expression? '1)
#f
> (is-quote-expression? (cons 'quote 1))
#f
> (is-quote-expression? (quote 42))
#f
> (is-quote-expression? (quote (quote 42)))
#t
Note how the built-in quote procedure simply returns what it is passed. In the case of (quote 42) it simply returns 42. But (quote (quote 42)) returns (quote 42), which is what you wish to pass to is-quote-expression?.
The behavior of quote is specified in R6RS, appendix A.3. For '1, the relevant rule is 6sqv:
(store (sf1 ...) S1[ 'sqv1 ]) → (store (sf1 ...) S1[ sqv1 ])
Time to break this down.
The "S → T" notation defines one step in evaluating a term, where "S" evaluates to "T".
Since store and the sf1 non-terminals appear the same on both the left and right sides, you don't need to understand them to understand how '1 evaluates. If you need something, think of store as "storage environment" and the sfn as pairs of names and values; (store ((x 1) (y 2)) S) means the identifier x is associated with the value 1 and y with 2 when evaluating the term S.
If you're not familiar with the S[e] notation, it refers to a term with one "hole" (an term with a [] in it) filled with e. There are two related syntax elements: terms with holes (S[]) and terms with a hole filled by a value (S[e]). Holes are a little (but only a little) like unnamed variables. One important difference is that a term is allowed only one hole. Holes are perhaps best explained by example. All of the following are S[]:
(+ [] 1 2)
(list [] 'a "foo")
(cond ((= x 0) [])
((> x 0) 1)
(else -1))
Note that a hole can only appear where a sub-term is syntactically valid; [] 2) is not a term-with-hole. S[0] would be a term with 0 substituted into the hole:
(+ 0 1 2)
(list 0 'a "foo")
(cond ((= x 0) 0)
((> x 0) 1)
(else -1))
When a value is given for a hole, the term S[] is also called a "context". This comes from one of the primary uses for terms-with-holes: to match any term containing the given value. S[e] is any term that contains e as a valid sub-term, so S[] is the context that e appears in. In short, S1['sqv1] is a stand-in for any term that contains a quote.
(+ 'foo 1 2)
(list 'bar 'a "foo")
(cond ((= x 0) 'baz)
((> x 0) 1)
(else -1))
Note the second term provides two different contexts for quote-terms: (list [] 'a "foo"), (list 'bar [] "foo"). This suggests that you shouldn't think of holes too much as just being unnamed variables.
If you're wonder why context terms and holes are used, they're an alternative to recursive definitions. Without contexts, → would have to be defined recursively over the structure of terms (Scheme's grammar defines the structure). Substitution in lambda calculus is an example of structural recursion, as are any tree-processing functions you might define in Scheme (though Scheme syntax is quite different than the syntax used to define → and lambda calculus substitution).
(define (tree-depth tree)
(if (pair? tree)
(max (tree-depth (car tree))
(tree-depth (cdr tree)))
1
) )
Next, let's examine the meaning of sqv, which is short for "self-quoting values". This is a non-terminal from the Scheme grammar, given in appendix A.2.
sqv ::= n | #t | #f
n ::= [numbers]
sqv is simply a number or boolean.
All together, the 6sqv evaluation rule means that a quoted number or boolean evaluates to the number or boolean; the quote is simply discarded.
What this signifies for your homework is that you can't tell the difference between 1 and '1 with a normal function, since sub-terms are evaluated before the function is called. You'll need a macro.
Why go through all this just to say that "'1 evaluates to 1"? Firstly, answering "why" takes more than answering "what". Also, it will hopefully help you go beyond the question, learning a little bit how to read Scheme's formal semantics, give you a taste of computational theory concepts and lead to many more questions.

Resources