What the difference between two if expression in Scheme? - scheme

I define a new version of if:
(define (new-if predicate then-clause else-clause)
(cond (predicate then-clause)
(else else-clause)))
Then I use it as the following:
(define (sqrt-iter guess x)
(new-if (good-enough? guess x)
guess
(sqrt-iter (improve guess x)
x)))
I understand that since the else-clause passed to new-if in the sqrt-iter procedure is always evaluated, sqrt-iter never stops making recursive calls to itself.
But I don't understand why we don't stop when good-enough? returns true => guess

Your new-if is a procedure. Procedure arguments are evaluated before being passed to the procedure. Therefore, your recursive sqrt-iter call is going to be evaluated fully before new-if is called. As Robert Harvey commented, this results in infinite recursion.
Your new-if needs to be a macro to function correctly. Something like:
(define-syntax new-if
(syntax-rules ()
((_ predicate then-clause else-clause)
(cond (predicate then-clause)
(else else-clause)))))

Related

Why this macro does not work in Racket

I am trying to have a macro which applies 'when' function when the 'else' statement is not given, otherwise 'if' is used:
(define-syntax-rule (myif condition body (body2 #f))
(if (not body2)
(when condition body)
(if condition
body
body2)))
(define x 15)
(myif (> x 10) (println x) )
However, this is not working. The error is:
myif: use does not match pattern:
(myif condition body (body2 #f)) in: (myif (> x 10) (println x))
define-syntax-rules doesn't take the arguments like a procedure with optional arguments.
(define-syntax-rule (myif condition body (body2 #f))
...)
Is the same as:
(define-syntax myif
(syntax-rules ()
[(myif condition body (body2 #f)) ...]))
A valid use would be (myif predicate consequence (alternative #f)) and it turns into:
(if (not (alternative #f))
(when predicate consequence)
(if predicate consequence (alternative #f)))
It seems you are trying to have code that should run compile time and not part of the expansion since this will evaluate the alternative before the predicate. That won't work with syntax-rules, however you can do what you want with having two patterns not using the simplified syntax:
(define-syntax myif
(syntax-rules ()
[(_ predicate consequence alternative) (if predicate consequence alternative)]
[(_ predicate consequence) (when predicate consequence)])
EDIT
So to do the same thing with a function imlpementing the macro instead. Here is a no thrills, no special feature implementation I could think of. NB: I'm a mere beginner when it comes to macros like these.
(define-syntax (myif stx)
(let ((lst (syntax->list stx)))
(if (= (length lst) 3)
#`(when #,#(cdr lst))
#`(if #,#(cdr lst)))))
Notice that the part of lst are syntax objects that have information of where it came from. `#, #,, and #,# are the syntax evivalent of `, ,, and ,#.

Contradictory assumptions on evaluator in SICP

Exercise 1.6 defines a new-if with cond:
(define (new-if predicate then-clause else-clause)
(cond (predicate then-clause)
(else else-clause)))
This new-if would fall into infinite loop when called in a recursion.
Example sqrt-iter illustrates the fact that arguments are evaluated immediately after passing into a user-defined function.
The (infinite)stream introduced in 3.5 is also defined a function:
(define (cons-stream a b)
(cons a
(delay b)))
The key point to build it, according to the text book, is delay.
But supposed you build a stream:
(define (intgers-starting-from n)
(cons-stream n
(intgers-starting-from (+ n 1))))
(define integers (intgers-starting-from 1))
Using the same evaluator as it in new-if, you won't get it working because (intgers-starting-from n) would always evaluate (intgers-starting-from (+ n 1)) and obviously there is no end to it despite how delay is implemented.
Is it contradictory that SICP assumes such evaluator that works for cons-stream but not for new-if?
SICP says:
Cons-stream is a special form defined so that
(cons-stream <a> <b>)
is equivalent to
(cons <a> (delay <b>))
It also adds:
Although stream-car and stream-cdr can be defined as procedures, cons-stream must be a special form. If cons-stream were a procedure, then, according to our model of evaluation, evaluating (cons-stream <a> <b>) would automatically cause <b> to be evaluated, which is precisely what we do not want to happen. For the same reason, delay must be a special form, though force can be an ordinary procedure.
By definition, a special form is not a procedure or function. So, your definition of cons-stream is incorrect.
It's usually implemented as a macro:
(define-syntax cons-stream
(syntax-rules ()
((cons-stream a b)
(cons a (delay b)))))
Indeed, you can define new-if as a macro and it'd work correctly too:
(define-syntax new-if
(syntax-rules ()
((new-if predicate then-clause else-clause)
(cond (predicate then-clause)
(else else-clause)))))

Maximum recursion error [duplicate]

I'm reading The Little Schemer. And thanks to my broken English, I was confused by this paragraph:
(cond ... ) also has the property of not considering all of its
arguments. Because of this property, however, neither (and ... ) nor
(or ... ) can be defined as functions in terms of (cond ... ), though
both (and ... ) and (or ... ) can be expressed as abbreviations of
(cond ... )-expressions:
(and a b) = (cond (a b) (else #f)
and
(or a b) = (cond (a #t) (else (b))
If I understand it correctly, it says (and ...) and (or ...) can be replaced by a (cond ...) expression, but cannot be defined as a function that contains (cond ...). Why is it so? Does it have anything to do with the variant arguments? Thanks.
p.s. I did some searching but only found that (cond ...) ignores the expressions when one of its conditions evaluate to #f.
Imagine you wrote if as a function/procedure rather than a user defined macro/syntax:
;; makes if in terms of cond
(define (my-if predicate consequent alternative)
(cond (predicate consequent)
(else alternative)))
;; example that works
(define (atom? x)
(my-if (not (pair? x))
#t
#f))
;; example that won't work
;; peano arithemtic
(define (add a b)
(my-if (zero? a)
b
(add (- a 1) (+ b 1))))
The problem with my-if is that as a procedure every argument gets evaluated before the procedure body gets executed. thus in atom? the parts (not (pair? x)), #t and #f were evaluated before the body of my-if gets executed.
For the last example means (add (- a 1) (+ b 1)) gets evaluated regardless of what a is, even when a is zero, so the procedure will never end.
You can make your own if with syntax:
(define-syntax my-if
(syntax-rules ()
((my-if predicate consequent alternative)
(cond (predicate consequent)
(else alternative)))))
Now, how you read this is the first part is a template where the predicate consequent and alternative represent unevaluated expressions. It's replaced with the other just reusing the expressions so that:
(my-if (check-something) (display 10) (display 20))
would be replaced with this:
(cond ((check-something) (display 10))
(else (display 20)))
With the procedure version of my-if both 10 and 20 would have been printed. This is how and and or is implemented as well.
You cannot define cond or and or or or if as functions because functions evaluate all their arguments. (You could define some of them as macros).
Read also the famous SICP and Lisp In Small Pieces (original in French).

"cond","and" and "or" in Scheme

I'm reading The Little Schemer. And thanks to my broken English, I was confused by this paragraph:
(cond ... ) also has the property of not considering all of its
arguments. Because of this property, however, neither (and ... ) nor
(or ... ) can be defined as functions in terms of (cond ... ), though
both (and ... ) and (or ... ) can be expressed as abbreviations of
(cond ... )-expressions:
(and a b) = (cond (a b) (else #f)
and
(or a b) = (cond (a #t) (else (b))
If I understand it correctly, it says (and ...) and (or ...) can be replaced by a (cond ...) expression, but cannot be defined as a function that contains (cond ...). Why is it so? Does it have anything to do with the variant arguments? Thanks.
p.s. I did some searching but only found that (cond ...) ignores the expressions when one of its conditions evaluate to #f.
Imagine you wrote if as a function/procedure rather than a user defined macro/syntax:
;; makes if in terms of cond
(define (my-if predicate consequent alternative)
(cond (predicate consequent)
(else alternative)))
;; example that works
(define (atom? x)
(my-if (not (pair? x))
#t
#f))
;; example that won't work
;; peano arithemtic
(define (add a b)
(my-if (zero? a)
b
(add (- a 1) (+ b 1))))
The problem with my-if is that as a procedure every argument gets evaluated before the procedure body gets executed. thus in atom? the parts (not (pair? x)), #t and #f were evaluated before the body of my-if gets executed.
For the last example means (add (- a 1) (+ b 1)) gets evaluated regardless of what a is, even when a is zero, so the procedure will never end.
You can make your own if with syntax:
(define-syntax my-if
(syntax-rules ()
((my-if predicate consequent alternative)
(cond (predicate consequent)
(else alternative)))))
Now, how you read this is the first part is a template where the predicate consequent and alternative represent unevaluated expressions. It's replaced with the other just reusing the expressions so that:
(my-if (check-something) (display 10) (display 20))
would be replaced with this:
(cond ((check-something) (display 10))
(else (display 20)))
With the procedure version of my-if both 10 and 20 would have been printed. This is how and and or is implemented as well.
You cannot define cond or and or or or if as functions because functions evaluate all their arguments. (You could define some of them as macros).
Read also the famous SICP and Lisp In Small Pieces (original in French).

Why do continuations not have useful arity?

Consider the following code:
(call-with-values
(lambda ()
(call/cc (lambda (k)
(k k k))))
(lambda (x y)
(procedure-arity y)))
It's pretty obvious here that the continuation at the point of the call/cc call is the lambda on the right-hand side, so its arity should be 2. However, the return value of the above (in Racket) is (arity-at-least 0) instead.
Indeed, running similar code in Guile (substituting procedure-minimum-arity for procedure-arity) shows that the continuation also supposedly allows any number of arguments, even though it's pretty clearly not the case.
So, why is that? As far as I understand (correct me if my understanding is wrong), the arity of a continuation is pretty straightforward: it's 1 except in the context of call-with-values, in which case it's whatever the arity of the right-hand-side lambda is. (Which, granted, can be complicated if it's a case-lambda or the like, but no more complicated than if you were calling (procedure-arity (case-lambda ...)) directly.)
A simpler way to see the same is:
(call-with-values
(lambda () (error 'arity "~v" (procedure-arity (call/cc (λ (k) k)))))
(lambda (x y) (procedure-arity y)))
and even simpler:
(procedure-arity (call/cc (λ (x) x)))
And for your question -- it's clear in the first case that the continuation expects two inputs, but cases like that are not too common. Eg, they're usually such examples, whereas "real code" would use define-values or have some unknown continuation, where the continuations that call/cc creates can have different arities depending on the context that they were created at. This means that there's not much point in trying to figure out these rare cases where the continuation's arity is known.
Footnote:
;; nonsensical, but shows the point
(define (foo) (call/cc (λ (x) x)))
(define x (foo))
(define-values [y z] (foo))

Resources