Lexical vs Dynamic interpreter in Scheme language - scheme

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.

Related

Racket: Trying to subtract numbers, getting list

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.

Difference between usage of set! and define

In the following code:
(define x 14)
(display x) ; x = 14
(set! x 13)
(display x) ; x = 13
(define x 14)
(display x) ; x = 14
(set! y 13) ; SchemeError: y not found!
(display y)
What we a use case where someone would want to use set! over just define, if define can be used for everything that set! can be used for + the actual definition itself?
define creates a new binding between a name and a value (a variable), set! mutates an existing binding. These are not the same operation, languages like Python which confuse the operations notwithstanding.
In particular something like
(define x 1)
...
(define x 2)
is illegal: you can only create the variable once. Implementations may not check this, but that doesn't make it legal. Once you've created the binding, if you want to modify it you need to do that with set!.
A particular case where implementations (including Racket) are intentionally sloppy about this is when they are being used interactively. Quite often if you're interacting with the system you may want to say, for instance:
> (define square (λ (x) (+ x x)))
... ooops, that's not right, is it?
... Better fix it using the command-line editing
> (define square (λ (x) (* x x)))
In cases like that it's clearly better for the implementation just to allow this repeated definition of things, because it's going to make the life of users enormously easier.
But in programs such repeated definitions in the same scope are (almost?) always bugs, and they really ought to be caught: if you want to mutate a binding, use set!. Racket in particular will certainly puke on these.
Finally note that define is simply not legal in all the places set! is: even in Racket (which allows define in many more places than Scheme does) this is not even slightly legal code:
(define (foo x)
(define v x)
(if (odd? x)
(define v (* v 2))
(define v (/ v 2)))
v)
While this is
(define (foo x)
(define v x)
(if (odd? x)
(set! v (* v 2))
(set! v (/ v 2)))
v)
(It's still terrible code, but it is legal.).

Meaning of this Scheme interpreter output?

I'm working through Simply Scheme. I'm using DrRacket with this as my definitions file
https://gist.github.com/alexgian/5b351f367169b40a4ad809f0bb718e1f
I'm on exercise 17.3, which says
https://people.eecs.berkeley.edu/~bh/ssch17/lists.html
Describe the value returned by this invocation of map
> (map (lambda (x) (lambda (y) (+ x y))) '(1 2 3 4))
In DrRacket, I get the following output for that invocation of map:
(#<procedure> #<procedure> #<procedure> #<procedure>)
I know that lambda lets you return procedures. I'm having a hard time figuring out what procedure is being returned for some reason though, what exactly is happening here.
Simply substitute in turn every value of the list to the variable x in the inner function. In other words, the result is equal to:
(list (lambda (y) (+ 1 y))
(lambda (y) (+ 2 y))
(lambda (y) (+ 3 y))
(lambda (y) (+ 4 y)))
a list of four functions, each of them increasing its parameter by a different value.

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.

Resources