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.
Related
I'm currently learning Racket/Scheme for a course (I'm not sure what's the difference, actually, and I'm not sure if the course covered that). I'm trying a basic example, implementing the Newton method to find a square root of a number; however, I ran into a problem with finding the distance between two numbers.
It seems that for whatever reason, when I'm trying to apply the subtraction operator between two numbers, it returns a list instead.
#lang racket
(define distance
(lambda (x y) (
(print (real? x))
(print (real? y))
(abs (- x y))
)
)
)
(define abs
(lambda x (
(print (list? x))
(if (< x 0) (- x) x)
)
)
)
(distance 2 5)
As you can see, I've added printing of the types of variables to make sure the problem is what I think it is, and the output of all those prints is #t. So:
In calling distance, x and y are both real.
In calling abs, x is a list.
So, the conclusion is that (- x y) returns a list, but why?
I double-checked with the documentation and it seems I'm using the subtraction operator correctly; I've typed (- 2 5) and then (real? (- 2 5)) into the same REPL I'm using to debug my program (Dr. Racket, to be specific), and I'm getting the expected results (-3 and #t, respectively).
Is there any wizard here that can tell me what kind of sorcery is this?
Thanks in advance!
How about this...
(define distance
(lambda (x y)
(print (real? x))
(print (real? y))
(abs (- x y))))
(define abs
(lambda (x) ;; instead of (lambda x ...), we are using (lambda (x) ...) form which is more strict in binding with formals
(print (list? x))
(if (< x 0) (- x) x)))
Read further about various lambda forms and their binding with formals.
I still do not understand how a dynamic interpreter differ from a lexical one.
I am working on scheme and i find it very difficult to know how a simple code like these one works dynamically and lexically.
(define mystery
(let ((x 2018))
(lambda (y)
(let ((result (cons x y)))
(set! x (+ x 1))
result))))
any guidance?
Lexical bindings have limited visibility and unlimited lifespan. All functions "remember" environment, where they were created- that kind of functions is called lexical closures.
In your example, this part:
(let ((x 2018))
(lambda (y) (let ((result (cons x y)))
(set! x (+ x 1)) result))))
returns function, which remembers environment with x = 2018. That function is bind to symbol mystery and when you call it, it changes value of x in that environment.
> (mystery 1)
'(2018 . 1)
> (mystery 1)
'(2019 . 1)
In Scheme with dynamic bindings (unlimited visibility, limited lifespan), functions don't remember environment, where they were created. So, function mystery won't remember environment with x = 2018 and call (mystery 1) ends with error during evaluation of (cons x y), because symbol x has no value.
Lets just make a program with your code:
;; a global binding
(define x 100)
;; your function
(define mystery
(let ((x 2018))
(lambda (y)
(let ((result (cons x y)))
(set! x (+ x 1))
result))))
;; just to add newlines in prints
(define displayln
(lambda (v)
(display v)
(newline)))
;; a indirect call
(define local-test
(lambda (x)
(displayln x)
(displayln (mystery 'local))
(displayln (mystery 'local))
(displayln x)))
(define global-test
(lambda ()
(displayln x)
(displayln (mystery 'global))
(displayln (mystery 'global))
(displayln x)))
;; program
(local-test 1)
(local-test 11)
(global-test 1)
(global-test 11)
Results from a normal Scheme relies only on closures and not about the call stack bound variables:
1
(2018 local)
(2019 local)
1
11
(2020 local)
(2021 local)
11
1
(2022 global)
(2023 global)
1
11
(2024 global)
(2025 global)
11
Results from a dynamic "Scheme" has the let in mystery as dead code. It does nothing since the bindings are not saved with the function object. Thus only the variables in active let and calls are matched:
1
(1 local)
(2 local)
3
11
(11 local)
(12 local)
13
100
(100 global)
(101 global)
102
102
(102 global)
(103 global)
104
(define mystery
(let ((x 2018))
(lambda (y)
(let ((result (cons x y)))
(set! x (+ x 1))
result))))
This is a not a very good example to understand the difference between dynamic and static binding. It's merely a corner case.
The idea is, in static binding the free variables are associated with the static scope (the lexical code that is visible when writing) and in dynamic binding, they are associated with the dynamic code (what is stored on the execution stack).
Your code evaluates to a result that is this lambda expression:
(lambda (y)
(let ((result (cons x y)))
(set! x (+ x 1))
result))
In this result, the only free variable is X.
What is the value of X when you apply the result to a value for Y?
In static scoping, it will be 2018, in dynamic binding the value of X will be stored on the stack--for example,
(define X 100)
(define F (result 200)))
will apply result with a bound X=100 (X's will be kept on the stack). Of course, X's value is not physically kept on the stack, just a pointer to the environment frame where it is, or maybe in a value cell if a rerooting is performed on the environment, etc.
To understand your misunderstanding you can take a course of lambda calculus. And, of course, what I said here supposes you use the common interpretation, many other interpretations can be associated to the same syntax as your input example, etc.
How can I create a method which takes two numbers and prepare a list from first number to second number. The first number is always positive and less than second number? I tried the following but the I am not sure how to have a global variable in Scheme to hold previous values.
(define preplist
(let ((temp '()))
(lambda (x y)
(cond ((= x y) (append temp (list x)))
(else (append temp (list x))
(display x)
(preplist (+ x 1) y))))))
Expected result is: (preplist 3 7) => (3 4 5 6 7)
Can some one please help to resolve this problem?
The solution for (x, y) can be computed as: put x on the front of (x+1, y). It is thus clearly recursive. Like this:
(define (preplist x y)
(if (= x y)
(list y)
(cons x (preplist (+ x 1) y))))
See, it works:
> (preplist 1 4)
(1 2 3 4)
> (preplist 5 7)
(5 6 7)
There are several mistakes in your code, for starters you don't need a global variable defined in a let for storing the result, it's enough to build the answer as you advance in the recursion. And don't use append in this case, if the solution template is followed closely, a cons will suffice for building the output list.
You should stick to the recipe for building a new list recursively; this is how the problem should be solved using that recipe, it's perhaps a bit more idiomatic like this:
(define preplist
(lambda (x y)
(cond ((> x y) ; if the exit condition is met
empty) ; then return the empty list
(else ; otherwise
(cons x ; cons the current element
(preplist (add1 x) y)))))) ; and advance the recursion
An altogether different approach would be to write a tail-recursive solution. This is more efficient because a constant amount of stack is used. It doesn't follow the design recipe as outlined above, but is somewhat more similar to the solution you had in mind - but bear in mind that this doesn't use global variables (only a named let for the iteration) and the solution is accumulated and passed around as a parameter:
(define (preplist x y)
(let loop ((i y) ; named let for iteration
(acc empty)) ; define and initialize parameters
(if (> x i) ; if exit condition is met
acc ; return accumulated value
(loop (sub1 i) ; otherwise advance recursion
(cons i acc))))) ; and add to the accumulator
Of course, as pointed by #dyoo in the comments, in a practical setting you'd use the built-in range procedure which does basically the same as the preplist procedure.
I'm making a function that multiplies all numbers between an 1 input and a "x" input with dotimes loop. If you please, check my function and say what's wrong since I don't know loops very well in Scheme.
(define (product x)
(let ((result 1))
(dotimes (temp x)
(set! result (* temp (+ result 1))))
result))
Use recursion. It is the way to do things in Scheme/Racket. And try to never use set! and other functions that change variables unless there really is no other choice.
Here's a textbook example of recursion in Scheme:
(define factorial
(lambda (x)
(if (<= x 1)
1
(* x (factorial (- x 1))))))
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.