What's the explanation for Exercise 1.6 in SICP? - recursion

I'm just beginning to work through SICP (on my own; this isn't for a class), and I've been struggling with Exercise 1.6 for a couple of days and I just can't seem to figure it out. This is the one where Alyssa re-defines if in terms of cond, like so:
(define (new-if predicate then-clause else-clause)
(cond (predicate then-clause)
(else else-clause))
She tests it successfully on some simple cases, and then uses it to re-write the square root program (which worked just fine with if):
(define (sqrt-iter guess x)
(new-if (good-enough? guess x)
guess
(sqrt-iter (improve guess x)
x)))
The question then asks: "What happens when Alyssa attempts to use this to compute square roots? Explain." [If necessary, I'm happy to reproduce the other procedures (good-enough?, improve, etc.), just let me know.]
Now, I know what happens: it never returns a value, which means that the program recurses infinitely. I just can't explain why this happens. Whatever subtle difference exists between if and new-if is eluding me. Any and all help much appreciated.

new-if is a function. When a function is called, what's the first thing that Scheme does with the argument list? It evaluates all the arguments.

new-if is a procedure, and Scheme uses applicative-order evaluation (1.1.5), so even before new-if is actually performed, it has to evaluate all the arguments first, which are guess and (sqrt-iter (improve guess x) x). You can see that the latter argument is a recursion, which calls a new new-if procedure, this is how the infinite loop occurs.
The ordinary if need not evaluate its arguments first, just go along the way, this is the difference between if and new-if. :)

First of all you have to understand the difference between applicative order evaluation and normal order. Lisp uses applicative order, but conditional expressions are evaluated not like normal functions (sicp chapter 1.1.6):
(if <predicate> <consequent> <alternative>)
To evaluate an if expression, the interpreter starts by evaluating the <predicate> part of the expression. If the <predicate> evaluates to a true value, the interpreter then evaluates the <consequent> and returns its value. Otherwise it evaluates the <alternative> and returns its value.

There are three ways a form may be evaluated in Scheme:
Applicative Order
evaluate the arguments and then apply
given f(x)=x+x: 3*f(1)*f(1) ⇒ 3*2*2
Normal Order
fully expand and then reduce
given f(x)=x+x: 3*f(1)*f(1) ⇒ 3*(1+1)*(1+1) (also used in "lazy evaluation")
Special Forms For example:
Booleans and and or. For example: (and <e1> ... <en>) evaluates Left → Right. If any evaluates to false, the value of the and expression is false, and the rest of the <e>'s are not evaluated.
Conditionals like if and cond
(if <predicate> <consequent> <alternative>): If the <predicate> evaluates to a true value, the interpreter then evaluates the <consequent> and returns its value. Otherwise it evaluates the <alternative> and returns its value
(cond (<p1> <e1>) ... (<pn> <en>)): The predicate <p1> is evaluated first. If its value is false, then <pn> is evaluated. If <pn>'s value is also false, then <pn+1> is evaluated. When true predicate, the interpreter returns the value of the corresponding consequent expression <e>.
In the case of Exercise 1.6:
new-if is a normal procedure. In Scheme (and many other languages), arguments are fully evaluated before the procedure is called. This is known as applicative order. ∴ sqrt-iter is called every time new-if is called, resulting in an infinite loop.
For the reader's edification, normal ifs are a special form. The recursive statement wouldn't be evaluated unless the <alternative> is called.

Previous answers are great. I'll add another one that explains in a more thorough way.
Another way to think of this difference is like this: How is the recursion using if stopping at some point and the one using new-if looping forever?
First lets see how these two ifs work in general and then how they work for this case.
if
This is explained by #alex-vasi:
To evaluate an if expression, the interpreter starts by evaluating the <predicate> part of the expression. If the <predicate> evaluates to a true value, the interpreter then evaluates the <consequent> and returns its value. Otherwise it evaluates the <alternative> and returns its value.
new-if
This is explained by #Schmudde:
All arguments are fully evaluated before the procedure is called.
How is the recursion using if stopping at some point?
It's stopping because at the point where the guess is good enough (ie (good-enough? guess x) is true), we will have:
(if (good-enough? guess x)
guess
(sqrt-iter (improve guess x)
x)))
And since the predicate is now true, the interpreter will evaluate the consequent (which is guess), return its value and will no longer evaluate the alternative (which is (sqrt-iter (improve guess x) x)).
So if actually evaluates (sqrt-iter (improve guess x) x) recursively up until the guess is good enough. Then it stops the recursion.
How is the recursion using new-if looping forever?
As with if, with new-if (sqrt-iter (improve guess x) x) will be evaluated recursively up until the guess is good enough.
But then it will keep evaluating (sqrt-iter (improve guess x) x) again and again. Why? Because when evaluating:
(new-if (good-enough? guess x)
guess
(sqrt-iter (improve guess x)
x)))
since new-if is a procedure, it will not check if (good-enough? guess x) is true or not in order to decide to evaluate either guess or (sqrt-iter (improve guess x)). What it will do is that it will evaluate (good-enough? guess x), guess and (sqrt-iter (improve guess x)) because those are the arguments of the procedure. So even when guess is good enough it will keep calling (sqrt-iter (improve guess x)) recursively :/.

Ex1.6. new-if:
(define (new-if predicate then-clause else-clause)
(cond (predicate then-clause)
(else else-clause)))
Difference with ‘if-statements’:
if-statements evaluate one by one from predicate -> consequent -> alternative,
however the ‘new-if’ has to evaluate all parameters aka arguments the MOMENT its called(which means 'else-clause' is evaluated at the start!!),
and thus this causes an infinite loop when any of these parameters call themselves into an iterative loop

Related

Racket Code: Higher-Order Functions

I'm trying to implement higher level functions in my Racket code, specifically with regards to this function:
(define (indivisible e L)
(map (remove 0 ((map ((lambda (x y) (modulo x y))) L e)))))
Essentially, I'm trying to remove all the elements that are divisible by e from the list. However, it keeps giving me an error that says that "the expected number of arguments did not match the given number (0 vs 2)". Why is this so?
Several places you have two sets of parentheses. Unless the parentheses are a part of a special form or macro, eg. let, it represent an application. Ie.
((lambda (x y) (modulo x y)))
Here the form (lambda ...) is evaluated and become a function. The second set of parentheses calls this function with no arguments. Since you have two arguments, x and y and not supplying any in your application it signals an error.
Another place where you do the same is around (map ....). Since I know map always evaluates to a list or null it looks kind of strange that you call it as a function ((map ...)).
If you are more familiar with algol languages like python, what you are doing is like someFunc(arg1 args2)() where you clearly see someFunc needs to return a function wince it's immediately called afterwards. The same in Scheme looks like ((some-func arg1 arg2)).
remove removes the first argument from the second argument list. It does not return a function so the outer map won't work.
To solve this I think you are looking for filter. You only need to make a predicate that is #f for the elements you don't want and you're done.

Why is cond a special form in Scheme, rather than a function?

(defun triangle-using-cond (number)
(cond
((<= number 0) 0) ; 1st
((= number 1) 1) ; 2nd
((> number 1) ; 3rd
;; 4th
(+ number
(triangle-using-cond (1- number))))))
Things that I know about Cond
It allows multiple test and alternative expressions
It has pre-specified evaluation order. For instance, the first condition will always evaluated whether it is right or not
One thing that I cannot distinguish is that what makes cond different from a function!
A function call (e0 e1 e2) is evaluated like this
1. e0 is evaluated, the result is (hopefully) a function f
2. e1 is evaluated, the result is a value v1
3. e2 is evaluated, the result is a value v2
4. The function body of `f` is evaluated in an environment in which
the formal parameters are bound to the values `v1` and `v2`.
Note that all expressions e0, e1, and, e2 are evaluated before the body of the function is activated.
This means that a function call like (foo #t 2 (/ 3 0)) will result in an error when (/ 3 0) is evaluated - before control is handed over to the body of foo.
Now consider the special form if. In (if #t 2 (/ 3 0)) the expressions #t is evaluated and since the value non-false, the second expression 2 is evaluated and the resulting value is 2. Here (/ 3 0) is never evaluated.
If in contrast if were a function, then the expressions #t, 2, and, (/ 3 0) are evaluated before the body of is activated. And now (/ 3 0) will produce an error - even though the value of that expressions is not needed.
In short: Function calls will always evaluate all arguments, before the control is passed to the function body. If some expressions are not to be evaluated a special form is needed.
Here if and cond are examples of forms, that don't evaluate all subexpressions - so they they need to be special forms.
If cond were not a special form then the expression:
((> number 1) ;;3rd
(+ number (triangle-using-cond (1- number))))
would cause either:
an infinite loop because triangle-using-cond would keep calling itself recursively via the tail call (triangle-using-cond (1- number)).
or, the last expression would try to apply the value #f or #t as a function (which in a type-2 Lisp such as ANSI Common Lisp is possible, but not possible in a type-1 Lisp such as Racket or Scheme) and produce an error.
What makes cond a special form is that its arguments are evaluated lazily whereas functions in Scheme or Common Lisp evaluate their arguments eagerly.
As already answered, all arguments to a call to some function f are evaluated before the result of applying f is computed. Does it however mean that cond, or if, or both should be special forms?
Well, first, if you have if, you can easily simulate a cond with nested tests. Conversely, if is just a degenerate form of cond. So you can say that it is sufficient to have one of them a special form. Let's choose if because it is simpler to specify.
So shall if be special?
It doesn't really need to...
If the underlying question is "is if expressible in terms of a smaller set of special forms?", then the answers is yes: just implement if in terms of functions:
(define true-fn (lambda (then else) (then)))
(define false-fn (lambda (then else) (else)))
Whenever you can return a boolean, you return one of the above function instead.
You could for example decide to bind #t and #f to those functions.
Notice how they call one of the two input parameters.
((pair? x) ;; returns either true-fn or false-fn
(lambda () (+ x 1))
(lambda () x))
...but why code in lambda calculus?
Evaluating code conditionally is really a fundamental operation of computing. Trying to find a minimal special forms where you cannot express that directly leads to a poorer programming language from the perspective of the programmer, however "clean" the core language is.
From a certain point of view, the if form (or cond) is necessary because without them it becomes really hard to express conditional execution in a way that a compiler/interpreter can handle efficiently.
This document referenced by uselpa discuss using closures to implement if, and concludes:
However, the syntactic inconvenience would be so great that even
Scheme defines if as a special form.

Scheme recursive or iterative

(define unique?
(lambda (l)
(or (null? l)
(null? (cdr l))
(and (not (in? (car l) (cdr l)))
(unique? (cdr l)))))
Can someone please tell me if it's an iteratibe or recursive procedure? I guess it is iterative, but I am not sure and I don't know how to explain i
You code is clearly recursive because unique? calls unique?. The procedure unique? will be iterative if the recursive call occurs in the tail position. The R6RS standard, see Section 11.20 'Tail calls and tail contexts', details the tail contexts for each syntactic form. Analyzing your lambda we reason as:
The last expression in a lambda is a tail context, so your or ... is a tail expression
The last expression in a or is a tail expression, so your and ... is a tail expression
The last expression in a and is a tail expression, so your unique? is a tail call
Therefore, unique? calls itself as a tail call and is thus iterative.
The function is recursive because it calls itself. Note, however that since it is tail-recursive, it can be compiled to iterative form.
The criteria for a function to be tail recursive is simply that there be nothing to do after the recursive call returns, which is true in your case.
How to convert a tail-recursive function into a loop
To transform a tail-recursive function into a while loop, follow the
following steps. (There is not an automatic function for converting an
arbitrary recursive function into a while loop--you have to convert it
into a tail-recursive function first.)
Turn the helper function parameters into local variables; their
initial values are the same as the initial values for the call to
the helper function from the main function.
The continue test is the same as the test in the helper function,
for the direction that causes a tail-recursive call to be made. (If
the tail-recursive call appears in the else part of the if, then add
a call to not.)
The body uses set! to update the value of each variable; the values
are the same as the arguments passed to the tail-recursive call.
Return the value of the accumulator; this comes after the while
loop.
Source: Tail recursion and loops
Since the other two answers explained what and why your function is tail-recursive; I am just going to leave an easy way for beginners to remember the difference:
A tail-recursive function does not operate on the recursive call.
A non-tail-recursive function does operate on the recursive call.

Functional "simultanity"?

At this link, functional programming is spoken of. Specifically, the author says this:
Simultaneity means that we assume a statement in lambda calculus is evaluated all at once. The trivial function:
λf(x) ::= x f(x)
defines an infinite sequence of whatever you plug in for x. The stepwise expansion looks like this:
0 - f(x)
1 - x f(x)
2 - x x f(x)
3 - x x x f(x)
The point is that we have to assume that the 'f()' and 'x' in step three million have the same meaning they did in step one.
At this point, those of you who know something about FP are muttering "referential transparency" under your collective breath. I know. I'll beat up on that in a minute. For now, just suspend your disbelief enough to admit that the constraint does exist, and the aardvark won't get hurt.
The problem with infinite expansions in a real-world computer is that.. well.. they're infinite. As in, "infinite loop" infinite. You can't evaluate every term of an infinite sequence before moving on to the next evaluation unless you're planning to take a really long coffee break while you wait for the answers.
Fortunately, theoretical logic comes to the rescue and tells us that preorder evaluation will always give us the same results as postorder evaluation.
More vocabulary.. need another function for this.. fortunately, it's a simple one:
λg(x) ::= x x
Now.. when we make the statement:
g(f(x))
Preorder evaluation says we have to expand f(x) completely before plugging it into g(). But that takes forever, which is.. inconvenient. Postorder evaluation says we can do this:
0 - g(f(x))
1 - f(x) f(x)
2 - x f(x) x f(x)
3 - x x f(x) x x f(x)
. . . could someone explain to me what is meant here? I haven't a clue what's being said. Maybe point me to a really good FP primer that would get me started.
(Warning, this answer is very long-winded. I thought it best to include general knowledge of lambda calculus because it is near impossible to find good explanations of it)
The author appears to be using the syntax λg(x) to mean a named function, rather than a traditional function in lambda calculus. The author also appears to be going on at length about how lambda calculus is not functional programming in the same way that a Turing machine isn't imperative programming. There's practicalities and ideals that exist with those abstractions that aren't present in the programming languages frequently used to represent them. But before getting into that, a primer on lambda calculus may help. In lambda calculus, all functions look like this:
λarg.body
That's it. There's a λ symbol (called "lambda", hence the name) followed by a named argument and only one named argument, then followed by a period, then followed by an expression that represents the body of the function. For instance, the identity function which takes anything and just returns it right back would look like this:
λx.x
And evaluating an expression is just a series of simple rules for swapping out functions and arguments with their body expressions. An expression has the form:
function-or-expression arg-or-expression
Reducing it usually has the rules "If the left thing is an expression, reduce it. Otherwise, it must be a function, so use arg-or-expression as the argument to the function, and replace this expression with the body of the function. It is very important to note that there is no requirement that the arg-or-expression be reduced before being used as an argument. That is, both of the following are equivalent and mathematically identical reductions of the expression λx.x (λy.y 0) (assuming you have some sort of definition for 0, because lambda calculus requires you define numbers as functions):
λx.x (λy.y 0)
=> λx.x 0
=> 0
λx.x (λy.y 0)
=> λy.y 0
=> 0
In the first reduction, the argument was reduced before being used in the λx.x function. In the second, the argument was merely substituted into the λx.x function body - it wasn't reduced before being used. When this concept is used in programming, it's called "lazy evaluation" - you don't actually evaluate (reduce) an expression until you need to. What's important to note is that in lambda calculus, it does not matter whether an argument is reduced or not before substitution. The mathematics of lambda calculus prove that you'll get the same result either way as long as both terminate. This is definitely not the case in programming languages, because all sorts of things (usually relating to a change in the program's state) can make lazy evaluation different from normal evaluation.
Lambda calculus needs some extensions to be useful however. There's no way to name things. Suppose we allowed that though. In particular, let's create our own definition of what a function looks like in lambda calculus:
λname(arg).body
We'll say this means that the function λarg.body is bound to name, and anywhere else in any accompanying lambda expressions we can replace name with λarg.body. So we could do this:
λidentity(x).x
And now when we write identity, we'll just replace it with λx.x. This introduces a problem however. What happens if a named function refers to itself?
λevil(x).(evil x)
Now we've got a problem. According to our rule, we should be able to replace the evil in the body with what the name is bound to. But since the name is bound to λx.(evil x), as soon as we try:
λevil(x).(evil x)
=> λevil(x).(λx.(evil x) x)
=> λevil(x).(λx.(λx.(evil x) x) x)
=> ...
We get an infinite loop. We can never evaluate this expression, because we have no way of turning it from our special named lambda form to a regular lambda expression. We can't go from the language with our special extension down to regular lambda calculus because we can't satisfy the rule of "replace evil with the function expression evil is bound to". There are some tricks for dealing with this, but we'll get to that in a minute.
An important point here is that this is completely different from a regular lambda calculus program that evaluates infinitely and never finishes. For instance, consider the self application function which takes something and applies it to itself:
λx.(x x)
If we evaluate this with the identity function, we get:
λx.(x x) λx.x
=> λx.x λx.x
=> λx.x
Using named functions and naming this function self:
self identity
=> identity identity
=> identity
But what happens if we pass self to itself?
λx.(x x) λx.(x x)
=> λx.(x x) λx.(x x)
=> λx.(x x) λx.(x x)
=> ...
We get an expression that loops into repeatedly reducing self self into self self over and over again. This is a plain old infinite loop you'd find in any (Turing-complete) programming language.
The difference between this and our problem with recursive definitions is that our names and definitions are not lambda calculus. They are shorthands which we can expand to lambda calculus by following some rules. But in the case of λevil(x).(evil x), we can't expand it to lambda calculus so we don't even get a lambda calculus expression to run. Our named function "fails to compile" in a sense, similar to when you send the programming language compiler into an infinite loop and your code never even starts as opposed to when the actual runtime loops. (Yes, it is entirely possible to make the compiler get caught in an infinite loop.)
There are some very clever ways to get around this problem, one of which is the infamous Y-combinator. The basic idea is you take our problematic evil function and change it to instead of accepting an argument and trying to be recursive, accepts an argument and returns another function that accepts an argument, so your body expression has two arguments to work with:
λevil(f).λy.(f y)
If we evaluate evil identity, we'll get a new function that takes an argument and just calls identity with it. The following evaluation shows first the name replacement using ->, then the reduction using =>:
(evil identity) 0
-> (λf.λy.(f y) identity) 0
-> (λf.λy.(f y) λx.x) 0
=> λy.(λx.x y) 0
=> λx.x 0
=> 0
Where things get interesting is if we pass evil to itself instead of identity:
(evil evil) 0
-> (λf.λy.(f y) λf.λy.(f y)) 0
=> λy.(λf.λy.(f y) y) 0
=> λf.λy.(f y) 0
=> λy.(0 y)
We ended up with a function that's complete nonsense, but we achieved something important - we created one level of recursion. If we were to evaluate (evil (evil evil)), we would get two levels. With (evil (evil (evil evil))), three. So what we need to do is instead of passing evil to itself, we need to pass a function that somehow accomplishes this recursion for us. In particular, it should be a function with some sort of self application. What we want is the Y-combinator:
λf.(λx.(f (x x)) λx.(f (x x)))
This function is pretty tricky to wrap your head around from the definition, so it's best to just call it Y and see what happens when we try and evaluate a few things with it:
Y evil
-> λf.(λx.(f (x x)) λx.(f (x x))) evil
=> λx.(evil (x x)) λx.(evil (x x))
=> evil (λx.(evil (x x))
λx.(evil (x x)))
=> evil (evil (λx.(evil (x x))
λx.(evil (x x))))
=> evil (evil (evil (λx.(evil (x x))
λx.(evil (x x)))))
And as we can see, this goes on infinitely. What we've done is taken evil, which accepts first one function and then accepts an argument and evaluates that argument using the function, and passed it a specially modified version of the evil function which expands to provide recursion. So we can create a "recursion point" in the evil function by reducing evil (Y evil). So now, whenever we see a named function using recursion like this:
λname(x).(.... some body containing (name arg) in it somewhere)
We can transform it to:
λname-rec(f).λx.(...... body with (name arg) replaced with (f arg))
λname(x).((name-rec (Y name-rec)) x)
We turn the function into a version that first accepts a function to use as a recursion point, then we provide the function Y name-rec as the function to use as the recursion point.
The reason this works, and getting waaaaay back to the original point of the author, is because the expression name-rec (Y name-rec) does not have to fully reduce Y name-rec before starting its own reduction. I cannot stress this enough. We've already seen that reducing Y name-rec results in an infinite loop, so the recursion works if there's some sort of condition in the name-rec function that means that the next step of Y name-rec might not need to be reduced.
This breaks down in many programming languages, including functional ones, because they do not support this kind of lazy evaluation. Additionally, almost all programming languages support mutation. That is, if you define a variable x = 3, later in the same code you can make x = 5 and all the old code that referred to x when it was 3 will now see x as being 5. This means your program could have completely different results if that old code is "delayed" with lazy evaluation and only calculated later on, because by then x could be 5. In a language where things can be arbitrarily executed in any order at any time, you have to completely eliminate your program's dependency on things like order of statements and time-changing values. If you don't, your program could calculate arbitrarily different results depending on what order your code gets run in.
However, writing code that has no sense of order in it whatsoever is extremely difficult. We saw how complicated lambda calculus got just trying to get our heads around trivial recursion. Therefore, most functional programming languages pick a model that systematically defines in what order things are evaluated in, and they never deviate from that model.
Racket, a dialect of Scheme, specifies that in the normal Racket language, all expressions are evaluated "eagerly" (no delaying) and all function arguments are evaluated eagerly from left to right, but the Racket program includes special forms that let you selectively make certain expressions lazy, such as (promise ...). Haskell does the opposite, with expressions defaulting to lazy evaluation and having the compiler run a "strictness analyser" to determine which expressions are needed by functions that are specially declared to need arguments to be eagerly evaluated.
The primary point being made seems to be that it's just too impractical to design a language that completely allows all expressions to be individually lazy or eager, because the limitations this poses on what tools you can use in the language are severe. Therefore, it's important to keep in mind what tools a functional language provides you for manipulating lazy expressions and eager expressions, because they are most certainly not equivalent in all practical functional programming languages.

Got some problems with CLISP's nested list and lambda expression

Nested lists in Common Lisp really confused me. Here is the problem:
By using recursion, let (nested-list 'b '(a (b c) d)) return t
if the first argument appears in the second argument (which could be
a nested list), and nil otherwise.
I tried find, but it only works if the first argument is '(b c).
I turned my eyes on lambda expressions. I want to flatten the second
argument first, and then use eq to compare the arguments.
(defun nested-list (x y)
(cond
((null y) ())
(t (append (lambda (flatten) (first y))
Then I got stuck. Even though I read a lot of stuff about lambda
expessions, it still confused me. I do not know how to recall it when
I need, I knew the funcall function, but you know I just cannot get
it. I just learnt Common Lisp for 5 days, so I hope you can give me a
hint. Thanks a lot!
First of all unless you mistyped if instead of iff the problem is quite trivial, just return t and you're done :-)
Seriously speaking instead when you need to solve a problem using recursion the idea often is simply:
if we're in a trivial case just return the answer
otherwise the answer is the same answer we'd get by solving a problem that it's just a little bit simpler that this, and we call ourself to solve this simplified version.
In the specific consider:
If the second argument is an empty list the answer is NIL
If the first argument is equal to the first element of the second argument then just return T instead
Otherwise if the first element of the second list is a list (therefore also possibly a nested list) and the element is contained in this multilist then return true (to check this case the function is calling itself)
Otherwise just check the same problem, but first dropping the first element of the second argument, because it has been checked (this also calls recursively the same function)
So basically 1 and 2 are the trivial cases; 3 and 4 are the cases in which you solve a simpler version of the problem.

Resources