Scheme result of a function - scheme

I have met the following code in Scheme:
(define x!
(lambda(x)
(if (= x 1) 1 (* x (x! (- x 1))))))
(define fact x!)
(define x! (lambda (x) x))
(fact 5)
Everything is clear for me until re-defining x! and seeing the result of the function (20).
How can it be explained?.. Why is it 20 and not 5!= 120.
Thanks in advance

Here's what's happening:
When you (define fact x!), you aren't permanently linking fact to x!. You're making fact equal to whatever x! is at the time of fact's definition.
So (define fact x!) is actually equivalent to:
(define fact
(lambda(x)
(if (= x 1) 1 (* x (x! (- x 1))))))
Next, you redefine x!:
(define x! (lambda (x) x))
But that does not change fact - it only changes x!. Next, you do this:
(fact 5)
Here's what the interpreter 'does' next (it may actually do it slightly differently - but only trivially so, and this should at least help you understand the behaviour of your program):
Replacing fact with its definition gives:
(lambda(x)
(if (= x 1) 1 (* x (x! (- x 1)))))
Replacing x! with its new definition gives:
((lambda(x)
(if (= x 1)
1
(* x
(- ((lambda (x)
x)
x)
1))))
5)
...Simplifying gives:
((lambda(x)
(if (= x 1)
1
(* x (- x 1))))
5)
...
(if (= 5 1)
1
(* 5 (- 5 1)))
...
(if #f
1
(* 5 (- 5 1)))
...Resolving the conditional and simplifying the substraction gives:
(* 5 4)
...Which yields 20.

The way Scheme behaves when you have a redefinition of an identifier is to use set! for it. In your case, if you replace the redefinition with
(set! x! (lambda (x) x))
then the result will become clearer.
(Note that this is not something that all schemes do...)

first you define x! to be the way to compute factorial (i.e. (x! 5) = 120).
Then you define fact to be what x! is, which is the same function (i.e. fact = lambda(x) (if (= x 1)...
Then you change what x! is the identity. However, fact is still that same function, you didn't change it, but that function references x! internally, so it ends up calling fact (which is the first thing you defined) which calls the identity function.
so (fact 5) is the same as:
(if (= 5 1) 1 (* 5 (x! (- 5 1))))))
which is the same as:
(if false 1 (* 5 (x! 4)))
which is the same as:
(if false 1 (* 5 4))
which is the same as:
(* 5 4)
which is 20

Ok, what happens here is the following:
When you do (x! (- x 1)) inside the original definition of x!, you're calling the function named x!. So if you change what the name x! means, that will affect this call to x!.
When you do (define fact x!) fact doesn't refer to the name x!, but to the current contents of x!, i.e. the function you just defined.
Now you change the meaning of the name x! and then call (fact 5). This will first invoke the original definition of x! (because that's what fact refers to), however when it gets to the call (x! (- 5 1)), it invokes the new definition of x!, which returns 4, so you get 5*4 = 20.

One side note: You need to use an environment model to figure it out.Because the answer of questions like that differs in lexical scoping versus dynamic scoping.

Related

Make procedure in Scheme by lambda

I am learning Scheme by 'Structure and Interpretation of Computer Programs'
In Chapter 1.3.2 Constructing Procedures Using lambda.
I understood lambda like this.
The value to match the lambda is written outside the parenthesis of the lambda.
((lambda (x) (+ x 4) 4) ; (x) is matched to 4, result is 8
But in SICP, another example code is different.
The code is :
(define (sum x y) (+ x y))
(define (pi-sum a b)
(sum (lambda (x) (/ 1.0 (* x (+ x 3))))
a
(lambda (x) (+ x 4))
b
))
(pi-sum 3 6)
I think if (lambda (x) (/ 1.0 (* x (+ x 3)))) want match to a, lambda and a must bound by parenthesis.
But in example code, don't use parenthesis.
When I run this code, error is occurs.
error is this :
***'sum: expects only 2 arguments, but found 4'***
When I use more parenthesis like this :
(define (sum x y) (+ x y))
(define (pi-sum a b)
(sum ((lambda (x) (/ 1.0 (* x (+ x 3))))
a)
((lambda (x) (+ x 4))
b)
))
(pi-sum 2 6) ; result is 10.1
Code is run.
I'm confused because of SICP's example code.
Am I right on the principle of lambda?
If I am right, why SICP write like that?
It says to use the sum from 1.3.1. On page 77 (actually starting on 77 and ending on 78) it looks like this:
(define (sum term a next b)
(if (> a b)
0
(+ (term a)
(sum term (next a) next b))))
As you can see it looks a lot different from your sum that just adds two number together. You also had a typo in pi-sum:
(define (pi-sum a b)
(sum (lambda (x) (/ 1.0 (* x (+ x 2)))) ; multiplied by 2, not 3!
a
(lambda (x) (+ x 4))
b))
(* 8 (pi-sum 1 1000))
; ==> 3.139592655589783
So the point here is that you can pass lambdas instead of named procedures. Since (define (name . args) body ...) is just syntax sugar for (define name (lambda args body ...)) passing (lambda args body ...) instead of defining it and pass a name is just an equal refactoring.
Parentheses around a variable (+) or a lambda ((lambda args body ...)) calls whatever procedure the operator expression evaluates. It is not what you want since you pass procedures to be used by sum as an abstraction. sum can do multiplications or any number of things based on what you pass. in sum term is the procedure (lambda (x) (/ 1.0 (* x (+ x 2)))) and you see it calls it as apart of its code.

Differences between two similar definitions

Is there any difference between
(define make-point cons)
and
(define (make-point x y)
(cons x y))
?
Is one more efficient than the other, or are they totally equivalent?
There are a few different issues here.
As Oscar Lopez points out, one is an indirection, and one is a wrapper. Christophe De Troyer did some timing and noted that without optimization, the indirection can take twice as much time as the indirection. That's because the alias makes the value of the two variables be the same function. When the system evaluates (cons …) and (make-point …) it evaluates the variables cons and make-point and gets the same function back. In the indirection version, make-point and cons are not the same function. make-point is a new function that makes another call to cons. That's two function calls instead of one. So speed can be an issue, but a good optimizing compiler might be able to make the difference negligible.
However, there's a very important difference if you have the ability to change the value of either of these variables later. When you evaluate (define make-point kons), you evaluate the variable kons once and set the value of make-point to that one value that you get at that evaluation time. When you evaluate (define (make-point x y) (kons x y)), you're setting the value of make-point to a new function. Each time that function is called, the variable kons is evaluated, so any change to the variable kons is reflected. Let's look at an example:
(define (kons x y)
(cons x y))
(display (kons 1 2))
;=> (1 . 2)
Now, let's write an indirection and an alias:
(define (kons-indirection x y)
(kons x y))
(define kons-alias kons)
These produce the same output now:
(display (kons-indirection 1 2))
;=> (1 . 2)
(display (kons-alias 1 2))
;=> (1 . 2)
Now let's redefine the kons function:
(set! kons (lambda (x y) (cons y x))) ; "backwards" cons
The function that was a wrapper around kons, that is, the indirection, sees the new value of kons, but the alias does not:
(display (kons-indirection 1 2))
;=> (2 . 1) ; NEW value of kons
(display (kons-alias 1 2))
;=> (1 . 2) ; OLD value of kons
Semantically they're equivalent: make-point will cons two elements. But the first one is creating an alias of the cons function, whereas the second one is defining a new function that simply calls cons, hence it'll be slightly slower, but the extra overhead will be negligible, even inexistent if the compiler is good.
For cons, there is no difference between your two versions.
For variadic procedures like +, the difference between + and (lambda (x y) (+ x y)) is that the latter constrains the procedure to being called with two arguments only.
Out of curiosity I did a quick and dirty experiment. It seems to be the case that just aliasing cons is almost twice as fast than wrapping it in a new function.
(define mk-point cons)
(define (make-point x y)
(cons x y))
(let ((start (current-inexact-milliseconds)))
(let loop ((n 100000000))
(mk-point 10 10)
(if (> n 0)
(loop (- n 1))
(- (current-inexact-milliseconds) start))))
(let ((start (current-inexact-milliseconds)))
(let loop ((n 100000000))
(make-point 10 10)
(if (> n 0)
(loop (- n 1))
(- (current-inexact-milliseconds) start))))
;;; Result
4141.373046875
6241.93212890625
>
Ran in DrRacket 5.3.6 on Xubuntu.

Calculating if a number is even or odd in scheme using tail recursion

I'm using the following functions in scheme48 to calculate if a number is even or odd.
(define (odds? x)
(if (= x 0) #f
((evens? (- x 1))
)))
(define (evens? x)
(if (= x 0) #t
((odds? (- x 1))
)))
However upon doing so I recieve the following error:
Error: attempt to call a non-procedure
(#t)
I would appreciate it if someone could explain what exactly this error means, and how to fix it.
There are a couple of erroneous () surrounding the last function call, and the formatting can be improved. Remember, in Scheme a pair of () means "function application" (that explains the error message attempt to call a non-procedure), so you have to be careful where you put them. Try this instead:
(define (odds? x)
(if (= x 0)
#f
(evens? (- x 1))))
(define (evens? x)
(if (= x 0)
#t
(odds? (- x 1))))

Let Statement/Random Function in Scheme

I was wondering if I would be able to use the built in let function from scheme to define two random variables within the function without their values changing throughout the code. For example if I wrote:
(let (x (- (* 2 (random)) 1)))
(let (y (- (* 2 (random)) 1)))
Would the value of x be constant until the function exits? I want to square x and y and take the square root of them, but I need their values to remain the same.
Yes, let binds a value to the given identifier, and its value doesn't change unless you use set! on it.
So you can do this:
(let ((x (- (* 2 (random)) 1))
(y (- (* 2 (random)) 1)))
(sqrt (+ (* x x) (* y y))))
Of course, I find it easier to define a hypot function for what you're doing (corresponding to C's hypot function):
(define (hypot x y)
(sqrt (+ (* x x) (* y y))))
(hypot (- (* 2 (random)) 1)
(- (* 2 (random)) 1))
Now you don't need to use let at all!
In case the connection isn't immediately obvious, the way let works behind the scenes is to create a function (with pretty much the same contents as hypot, in this case), and just calls that function with the values you're binding. So, the two snippets of code above are effectively identical (except that the latter one also adds a top-level binding for hypot).

What am I doing wrong with Scheme?

When I enter the following:
(define (root a b c)
(/ (+ (-b) (sqrt (- (exp b 2) (* 4 a c)))) (* 2 a)))
and then enter:
(root 3 6 2)
I get a message indicating that the procedure had two arguments but only requires exactly one. What am I doing wrong?
The exp function doesn't do exponents really, it does something else mathy. (I don't know.)
What you want is usually called pow for "power" but probably isn't defined in your environment, so I suggest you just define your own square method:
(define (square x) (* x x))
And then:
(define (root a b c)
(/ (+ (- b) (sqrt (- (square b) (* 4 a c)))) (* 2 a)))
Edit: Oh, you'll also have to change a couple spacing issues, like (* 4 a c) instead of (*4 a c), and (- b) instead of (-b). You always have to separate the operator from the operands with spaces.
The procedure exp raises the number e to the power of its argument, if you need to raise an argument to the power of another argument, use expt. Even better, given that you only need to square b, a simple multiplication will do. Like this:
(define (root a b c)
(/ (+ (- b) (sqrt (- (* b b) (* 4 a c))))
(* 2 a)))
The function the error refers to is exp which takes only one argument. The exp function calculates the exponential function, not an exponent. You want expt, which raises a root x to the exponent y:
(expt b 2)
You can also just multiply the number times itself.
I usually keep R5RS or The Scheme Programming Language on hand since these basic functions can be hard to keep straight.

Resources