Meaning of this Scheme interpreter output? - scheme

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.

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.

Lexical vs Dynamic interpreter in Scheme language

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.

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.

SICP Exercise 2.04

Reading SICP I am now at exercise 2.04, which is a procedural representation of cons, car and cdr, given in the book as follows:
(define (cons x y)
(lambda (m)
(m x y)))
(define (car z)
(z
(lambda (p q)
(p))))
Note, that for running the code I use racket with the following preamble in my code:
#lang racket
(define (Mb-to-B n) (* n 1024 1024))
(define MAX-BYTES (Mb-to-B 64))
(custodian-limit-memory (current-custodian) MAX-BYTES)
I also tried #lang scheme to no avail.
Here is what I understand:
About cons
cons returns a function.
This function which will apply another function given as parameter to the two parameters x and y of cons.
This means by calling cons we retain the possibility to apply a function to the two parameters and are able to treat them as some unit.
About car
car now uses the fact, that we can apply a function to the unit of 2 values given to cons, by giving a function as a parameter to the function, which we get returned from cons.
It supplies that function with a lambda expression, which always returns the first of two given values.
Usage
At first I tried the following:
(car (cons 1 2))
(car (cons 2 3))
(car (cons (cons 1 1) (cons 2 2)))
(car (car (cons (cons 1 1) (cons 2 2))))
However, that leads to errors:
:racket -l errortrace -t exercise-2.04-procedural-representation-of-pairs.rkt
application: not a procedure;
expected a procedure that can be applied to arguments
given: 1
arguments...: [none]
errortrace...:
/home/xiaolong/development/LISP/Racket/SICP/exercise-2.04-procedural-representation-of-pairs.rkt:24:6: (p)
/home/xiaolong/development/LISP/Racket/SICP/exercise-2.04-procedural-representation-of-pairs.rkt:33:0: (car (cons 1 2))
context...:
/home/xiaolong/development/LISP/Racket/SICP/exercise-2.04-procedural-representation-of-pairs.rkt: [running body]
I could not understand what was wrong with my code, so I looked up some usage examples in other people's solutions. One is on http://community.schemewiki.org/?sicp-ex-2.4:
(define x (cons 3 4))
(car x)
But to my surprise, it doesn't work! The solution in the wiki seems to be wrong. I get the following error:
application: not a procedure;
expected a procedure that can be applied to arguments
given: 3
arguments...: [none]
errortrace...:
/home/xiaolong/development/LISP/Racket/SICP/exercise-2.04-procedural-representation-of-pairs.rkt:24:6: (p)
/home/xiaolong/development/LISP/Racket/SICP/exercise-2.04-procedural-representation-of-pairs.rkt:42:0: (car x)
context...:
/home/xiaolong/development/LISP/Racket/SICP/exercise-2.04-procedural-representation-of-pairs.rkt: [running body]
What am I doing wrong here?
You have an error in your code. Instead of:
(define (car z)
(z
(lambda (p q)
(p))))
you should have written (see the book):
(define (car z)
(z
(lambda (p q)
p)))
Note that in the last row p is written without parentheses.
The message: application: not a procedure means that p is not a procedure (it is actually a number), while with the notation (p) you are calling it as a parameterless procedure.

build-list (error - expects a procedure) Racket/Scheme

Trying to make a function that produces a n by n board
(new-board 2)
is supposed to produce
(list (make-posn 0 0) (make-posn 0 1) (make-posn 1 0) (make-posn 1 1))
The current rendition of my code is as follows:
(define (new-board y)
(build-list y (lambda (x) (build-list x (make-posn y x))))
)
I was pretty certain that it would work, but given my current knowledge and experience in Racket, I couldn't find the error.
I typed in:
> (new-board 3)
and got the error:
build-list: expects a procedure (arity 1); given (make-posn 3 0)
Am I committing a heinous crime by invoking build list inside of a build-list?
Please let me know. Thanks!
About this procedure:
(define (new-board y)
(build-list y (lambda (x) (build-list x
(make-posn y x))))) ;error!
Let's see what build-list receives as parameters. The first parameter is y, a number and the second parameter is a procedure, but you're passing the result of evaluating make-posn, which is not a procedure, it's a value. And that's the reason for the error you're getting.
EDIT 1 :
Now I understand what you intended. I can think of a solution, but it's a bit more elaborated than what you had in mind:
(define (new-board n)
(flatten
(map (lambda (x)
(map (lambda (y)
(make-posn x y))
(build-list n identity)))
(build-list n identity))))
(define (flatten lst)
(if (not (list? lst))
(list lst)
(apply append (map flatten lst))))
Here's how it works:
build-list is just being used for generating numbers from 0 to n-1, and I'm passing identity as the procedure, because no further processing is required for each number
For each number in the list, we also want to generate another list, again from 0 to n-1 because all the coordinates in the board are required. For example if n is 3 the coordinates are '((0 0) (0 1) (0 2) (1 0) (1 1) (1 2) (2 0) (2 1) (2 2))
I'm using a map inside a map for building the nested lists, a technique borrowed from here (see: "nested mappings")
Finally, I had to flatten the generated lists, and that's what flatten does (otherwise, we'd have ended with a list of lists of lists)
EDIT 2 :
Come to think of it, I found an even simpler way, closer to what you had in mind. Notice that the flatten procedure is unavoidable:
(define (new-board n)
(flatten
(build-list n
(lambda (x)
(build-list n
(lambda (y)
(make-posn x y)))))))
Now, when you type this:
(new-board 2)
The result is as expected:
(#(struct:posn 0 0) #(struct:posn 0 1) #(struct:posn 1 0) #(struct:posn 1 1))
If you look up the signature (contract) of build-list1, you see that it is
build-list : Nat (Nat -> X) -> (listof X)
So it takes a (natural) number, and then a function that expects a natural number and gives back an element of the type (X) that you want included in the list. So in your case, what specific type do you want X to be for each call you're making to build-list (it can be different in each case). In the case of the inner build-list, it looks like you're trying to make a list of posns. However, (make-posn y x) immediately makes a single posn and is not a function as build-list expects. So just as you provide a function (lambda (x) ...) to the outer build-list, you should also provide a function (lambda (...) ...) to the inner function.
Choosing the name x for the parameter of the first lambda might be a little confusing. What I might do is change the name of the new-board function's parameter to N, in that it seems like you want to create a board of N rows (and columns). And the purpose of the first build-list is to create each of those rows (or columns, depending how you want to think of it). So if you had:
(define (new-board N)
(build-list N (lambda (x) ...)))
And then you use it like:
(new-board 5)
it will reduce/simplify/evaluate as follows:
==> (build-list 5 (lambda (x) ...))
==> (list ( (lambda (x) (build-list ... x ...)) 0 )
( (lambda (x) (build-list ... x ...)) 1 )
( (lambda (x) (build-list ... x ...)) 2 )
( (lambda (x) (build-list ... x ...)) 3 )
( (lambda (x) (build-list ... x ...)) 4 )
==> (list (build-list ... 0 ...)
(build-list ... 1 ...)
(build-list ... 2 ...)
(build-list ... 3 ...)
(build-list ... 4 ...))
So, there's nothing wrong with nesting build-list. See if you can figure out now how to have the inner build-list work on producing a list of posns once the current row is fixed to a particular x value.
By the way, if you're allowed to use full Racket, there's a nice way to express the computation with for loops:
(define (new-board n)
(for*/list ([i n]
[j n])
(make-posn i j)))
Another way to get the same result but with a different approach is to use an arithmetic trick with quotient and remainder.
(define (new-board n)
(build-list (* n n)
(lambda (k)
(make-posn (quotient k n)
(remainder k n)))))

Resources