I'm learning racket and I have a question about when to use define and when to use let.
I have this function:
(define my-function
(lambda (param1 param2 list1)
(/
(count
(lambda (x)
(define a (param1 (remove x list1)))
(define b (drop-right x 1))
(define c (param2 a x-sin-clase))
(eq? (last x) (last c)))
(cdr list1))
(length (cdr list1)))))
Without knowing what the above function does. Is it correct to use define inside the function body?
I have read somewhere that define is used to declare global variables and let is used to declare local variables. I've look in racket's documentation but it doesn't talk about any difference.
One difference: Internal defines are in a mutually recursive scope, but let bindings are not.
This means than in a let:
(let ([x expr-1] [y expr-2])
body)
The expr-1 and expr-2 cannot refer to x or y. More concretely,
(let ([x (stream-cons 1 y)] [y (stream-cons 2 x)])
x)
;error=> y: unbound identifier in: y
And if x or y is defined outside of the let, expr-1 and expr-2 will refer to the outer definitions, and not the ones introduced by the let. Concretely:
(define x 'outer)
(let ([x 'inner] [y x]) ; <- this x refers to outer,
y) ; so y is 'outer
;=> 'outer
However, internal defines have a mutually recursive scope, which means that in
(block
(define x expr-1)
(define y expr-2)
body)
The expr-1 and expr-2 can refer to x or y. Concretely,
(require racket/block)
(block
(define x (stream-cons 1 y))
(define y (stream-cons 2 x))
(stream->list (stream-take x 5)))
;=> (list 1 2 1 2 1)
The Scope of a define
....A....
(define (f)
(define t1 ..B..)
(define x ..C..)
(define t2 ..D..)
....E....)
....F....
The x is visible everywhere in the body of f, but not outside that. That means it's visible in B, C, D, and E, but not in A or F.
The Scope of a let
....A....
(define (f)
(let ([t1 ..B..]
[x ..C..]
[t2 ..D..])
....E....))
....F....
Here the x is visible everywhere in the body of the let, but not outside that. That means it's visible in E, but not in A, B, C, D, or F.
The Scope of a let*
....A....
(define (f)
(let* ([t1 ..B..]
[x ..C..]
[t2 ..D..])
....E....))
....F....
Here the x is visible everywhere in the body of the let* and in let* bindings that come after it, but not outside that. That means it's visible in D and E, but not in A, B, C, or F.
The Scope of a letrec
....A....
(define (f)
(letrec ([t1 ..B..]
[x ..C..]
[t2 ..D..])
....E....))
....F....
The x is visible everywhere in the body of the letrec and in the bindings of the letrec, but not outside that. That means it's visible in B, C, D, and E, but not in A or F.
The scope of variables in letrec and the scope of local define variables are very similar because both letrec and define work with mutually recursive scopes.
I've finally understood what I have read that define's variable are "global variables".
In the book The Scheme Programming Language Fourth Edition, R. Kent Dybvig, section 2.6. Top Level Definitions says:
The variables bound by let and lambda expressions are not visible
outside the bodies of these expressions.
Related
syntax-rules in Scheme are "hygienic" and "referentially transparent" and must preserve Scheme's lexical scoping. From my understanding, this means that during the macro expansion phase, the expander would need to know about lambda and define.
The expander needs to know about lambda.
Suppose we have this code:
(define x 1)
((lambda (x) x) 2)
If the expander did not know about the lambda special form, it would consider the two xs in (lambda (x) x) to be bound to the x in (define x 1), which is incorrect.
The expander needs to know about define, so that it knows where (i.e. in which scope) a particular identifier is defined. In addition, suppose we have this code:
(define n 1)
(define f (lambda (x y) (+ x y)))
(define lambda f)
(lambda n n)
In order to correctly determine that both n in (lambda n n) refer to (define n 1), the expander has to understand that (define lambda f) has changed the meaning of lambda (and therefore the expander has to stop using special rules for handling lmabda in this scope).
What other special forms does the macro expander need to know about? Does it need to know about set!?
The examples seem to be about lexical scoping, not macro expansion.
(define x 1)
((lambda (x) x) 2)
The binding of x in the second line shadows that in the first.
Similarly in the second example (define lambda f) binds lambda
in the region following the define; there is no macro expansion.
The identifier lambda can be used as a keyword in a syntactic extension (macro);
lexical scoping applies normally, there are no special rules:
> (let-syntax ([lambda (syntax-rules ()
[(lambda arg) ((lambda (x) (+ 1 x)) arg)])])
(lambda 2))
3
>
But:
> (letrec-syntax ([lambda (syntax-rules ()
[(lambda arg) ((lambda (x) (+ 1 x)) arg)])])
(lambda 2))
Exception: invalid syntax (lambda (x) (+ 1 x))
>
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.).
The code below, under dynamic scope assumption, would return error.
(let ((f (lambda (g)
(lambda (n)
(if (zero? n)
1
(* n ((g g) (- n 1))))))))
((f f) 5))
My answer was 0, because:
n*(n-1)*(n-2)*(n-3)*(n-3)*(n-4)*1;; since the call with n=0, n bound to 0
0*0*0*0*1
What am I missing here?
(define test
(let ((x 10))
(lambda () x)))
Here we return lambda function from the scope where x is a local variable. Under lexical scope an environment gets attached to the created lambda function. This environment consists of the bound variables on top of the free variables that were available when the lambda function was being created -- here, x, bound to 10. Thus when this returned lambda function is called, its x can only be 10.
In dynamic scope the let is dead code. The lambda function that is created does not store its lexical environment and thus when it will be called, x will be looked up fresh, at the actual time of the call. The variable that was called x with value 10 will no longer exist by then. The x looked up by the lambda will be whatever you have x bound to, at the call time:
(let ((x 20))
(test))
; ==> 20
And of course:
(test); == ERROR: Unbound variable x
So to your code it's the same problem. Whatever g is when (lambda (n) ...) is evaluated, creating the lambda function, goes out of scope when that lambda function is returned, and thus when that returned lambda function is called, g will be looked up fresh, and will be whatever g is bound to at the time of calling, as before. In order for this to work in a dynamic scope you could do this:
(let ((f (lambda (g n)
(if (zero? n)
1
(* n (g g (- n 1)))))))
(f f 5))
The difference here is that g never goes out of scope. This works in both dynamic and lexical scope. You can simplify it for dynamic scope like this:
(let ((f (lambda (n) ; ((lambda (f) (f 5))
(if (zero? n) ; (lambda (n)
1 ; (if (zero? n)
(* n (f (- n 1))))))) ; 1
(f 5)) ; (* n (f (- n 1))))))
In lexical scope the f inside (lambda (n) ...) is unbound variable, but in a dynamic scope f is first established, and after the call (f 5) it remains available for all the nested calls, (f 4), (f 3) etc., until the evaluation of (f 5) inside (lambda (f) (f 5)) is finished; only then that f is disestablished, destroyed, when that lambda is exited returning the result of (f 5).
In Paul Grahams nice wrap-up of McCarthys original lisp paper he mentions that there was a bug in the paper. The very first higher order function, maplist, had x as the name for the list argument. In the demonstration diff he passes a function to maplist that has x as a parameter. These two collide after the first pair and thus it does not work because of dynamic scope. Dynamic scope is extremely error prone and in Common Lisp where all globals are dynamic, the *earmuffs* naming convention is a necessity to avoid countless hours finding the global that changed the function to do something completely different than expected.
Using dynamic scope, g will be undefined because there is no variable named g on line 6.
I am trying to understand concepts of lexical and dynamic scoping and the differences between them.
Let's take a look at the following code:
(let ((a 1)
(b 2))
(letrec ((f (lambda () F))
(g (lambda (c) G)))
(lambda (d)
(+ (f) (g b)))))
For expressions F and G, which variables are at lexical scope of (lambda(d)...)?
(lambda(d)...) has d as bound variable and f, g a b and all of the global scope as free variables.
EDIT
Just to demonstrate the code in Scheme and some other language where the same bindings are dynamic. Since neither of your functions call each other you might as well keep them in the same let:
(define test
(let ((a 1)
(b 2)
(f (lambda () F))
(g (lambda (c) G)))
(lambda (d)
(+ (f) (g b)))))
;; for the test we need the F and G defined
(define F 10)
(define G 20)
(test 4) ; ==> 30 (aka (+ F G))
What happens is that when the lambda gets evaluated the variables it uses from the lexical scope lives on even after the let is gone. In a dymaic scope this isn't true:
(test 4)
; ERROR f: unbound identifier
The reason for this is while a, b, f and g existed when the lamba was evaluated none of the variables get captured like in lexical scope and thus when the procedure test is made none of the local variables exist anymore. In fact you might as well write it like this:
;; in a dynamic lisp this s the same
(define test
(lambda (d)
(+ (f) (g b))))
And you must make sure the variable exist when you call the function (aka dynamic)
(define g (lambda (v) 1337))
(define f (lambda () 3.1415927))
(define b 13)
(test 4) ; ==> 1340.1415927
Now if you were to add the above definitions in the global scope and keep the original definition you'd still get 30 since a lexical lisp uses the closer lexical bindings rather than the global ones.
Another great example is this:
(define x 10)
(define (test v)
(+ x v))
(let ((x 20))
(test 10))
; ==> ?
In a lexical lisp the result would be always 20 since test does not have any idea of the let since it is not in its lexical scope. It's x is always the global bindings x. In a dymamic lisp the x from the let is the closest one from the runtime point of view which would result in 30 since the x in test is the same as the x in the let and it shadows the global x.
I was just beginning to feel I had a vague understanding of the use of lambda in racket and scheme when I came across the following 'alternate' definitions for cons and car in SICP
(define (cons x y)
(lambda (m) (m x y)))
(define (car z)
(z (lambda (p q) p)))
(define (cdr z)
(z (lambda (p q) q)))
For the life of me I just cannot parse them.
Can anybody explain how to parse or expand these in a way that makes sense for total neophytes?
This is an interesting way to represent data: as functions. Notice that this
definition of cons returns a lambda which closes over the parameters x
and y, capturing their values inside. Also notice that the returned lambda
receives a function m as a parameter:
;creates a closure that "remembers' 2 values
(define (cons x y) (lambda (m) (m x y)))
;recieves a cons holding 2 values, returning the 0th value
(define (car z) (z (lambda (p q) p)))
;recieves a cons holding 2 values, returning the 1st value
(define (cdr z) (z (lambda (p q) q)))
In the above code z is a closure, the same that was created by cons, and in
the body of the procedure we're passing it another lambda as parameter,
remember m? it's just that! the function that it was expecting.
Understanding the above, it's easy to see how car and cdr work; let's
dissect how car, cdr is evaluated by the interpreter one step at a time:
; lets say we started with a closure `cons`, passed in to `car`
(car (cons 1 2))
; the definition of `cons` is substituted in to `(cons 1 2)` resulting in:
(car (lambda (m) (m 1 2)))
; substitute `car` with its definition
((lambda (m) (m 1 2)) (lambda (p q) p))
; replace `m` with the passed parameter
((lambda (p q) p) 1 2)
; bind 1 to `p` and 2 to `q`, return p
1
To summarize: cons creates a closure that "remembers' two values, car
receives that closure and passes it along a function that acts as a selector for
the zeroth value, and cdr acts as a selector for the 1st value. The key
point to understand here is that lambda acts as a
closure.
How cool is this? we only need functions to store and retrieve arbitrary data!
Nested Compositions of car & cdr are defined up to 4 deep in most LISPs. example:
(define caddr (lambda (x) (car (cdr (cdr x)))))
In my view, the definitive trick is reading the definitions from the end to the beginning, because in all three of them the free variables are always those that can be found in the lambda within the body (m, p and q). Here is an attempt to translate the code to English, from the end (bottom-right) to the beginning (top-left):
(define (cons x y)
(lambda (m) (m x y))
Whatever m is, and we suspect it is a function because it appears right next to a (, it must be applied over both x and y: this is the definition of consing x and y.
(define (car z)
(z (lambda (p q) q)))
Whatever p and q are, when something called z is applied, and z is something that accepts functions as its input, then the first one of p and q is selected: this is the definition of car.
For an example of "something that accepts functions as its input", we just need to look back to the definition of cons. So, this means car accepts cons as its input.
(car (cons 1 2)) ; looks indeed familiar and reassuring
(car (cons 1 (cons 2 '()))) ; is equivalent
(car '(1 2)) ; is also equivalent
(car z)
; if the previous two are equivalent, then z := '(1 2)
The last line means: a list is "something that accepts a function as its input".
Don't let your head spin at that moment! The list will only accept functions that can work on list elements, anyway. And this is the case precisely because we have re-defined cons the way that we have.
I think the main point from this exercise is "computation is bringing operations and data together, and it doesn't matter in which order you bring them together".
This should be easy to understand with the combinatory notation (implicitly translated to Scheme as currying functions, f x y = z ==> (define f (λ (x) (λ (y) z)))):
cons x y m = m x y
car z = z _K ; _K p q = p
cdr z = z (_K _I) ; _I x = x _K _I p q = _I q = q
so we get
car (cons x y) = cons x y _K = _K x y = x
cdr (cons x y) = cons x y (_K _I) = _K _I x y = _I y = y
so the definitions do what we expect. Easy.
In English, the cons x y value is a function that says "if you'll give me a function of two arguments I'll call it with the two arguments I hold. Let it decide what to do with them, then!".
In other words, it expects a "continuation" function, and calls it with the two arguments used in its (the "pair") creation.