Reputation: 33
Hi I am trying to understand the output of the following code
(define p (lambda (x) (lambda (y) (x (x y)))))
(define q (lambda (x) (* x x)))
when I use
(map (p q) (list 1 2 3))
the result is
(1 16 81)
shouldn't the answer be
(1 4 9) ?
Upvotes: 0
Views: 165
Reputation: 820
Francis King's answer is very clear, this is just an extended footnote inspired by it.
Replacing identifiers with mnemonic ones (rewriting q
as square
) can make it easier to understand code [1]
Procedures as [first-class] values in Scheme [2] are often introduced with examples using lambda
:
> (define twelve 12)
> (define square (lambda (x) (* x x)))
> (square twelve)
144
>
just as the characters 12
in the code above are the representation of a Number,
the characters (lambda (x) (* x x))
are the representation of a Procedure:
(number? 12)
=> #t, (procedure? (lambda (x) (* x x)))
=> #t
Two further code rewritings may be helpful:
using the "short-form" define
for procedures, and annotating the definition
with a type signature (argument and result types):
> (define (square x) (* x x)) ;; Number -> Number
> (square 3)
9
> (define (do-twice f x) ;; (X -> X) X -> X
(f (f x)))
> (do-twice square 3)
81
> (map (lambda (x) (do-twice square x))
'(1 2 3))
(1 16 81)
>
Note that this do-twice
does not yet correspond to the p
of the question: making
this do-twice the first argument of map would require:
(map do-twice (make-list 3 square) '(1 2 3))
Mapping one list needs a function of one argument, so something has to produce the do-twice of
(define (do-twice x) (f (f x)))
as its value:
> (define (do-twice-with f) ;; (X -> X) -> (X -> X)
(define (do-twice x) ;; X -> X
(f (f x)))
do-twice)
> ((do-twice-with square) 3)
81
> (map (do-twice-with square)
'(1 2 3))
(1 16 81)
>
So do-twice-with
is the function p
in the question.
do-twice-with
requires a function argument (X -> X), but X can be any type, so:
> (define (repeat s) ;; String -> String
(string-append s " " s))
> ((do-twice-with repeat) "buffalo")
"buffalo buffalo buffalo buffalo"
and do-twice-with
itself has type (X' -> X') (with X' standing for (X -> X)), so can be
applied to itself:
> (((do-twice-with do-twice-with) square) 3)
43046721
> (((do-twice-with do-twice-with) repeat) "buffalo") [3]
"buffalo buffalo buffalo buffalo buffalo buffalo buffalo buffalo buffalo buffalo buffalo buffalo buffalo buffalo buffalo buffalo"
((((do-twice-with do-twice-with) do-twice-with) square) 3)
is left as an
exercise for the reader...
[1] "Naming is perhaps the most powerful abstracting notion we have" [Guy L Steele]
[2] https://walker.cs.grinnell.edu/courses/151.sp04/readings/procedures-as-values.xhtml
[3] https://en.wikipedia.org/wiki/Buffalo_buffalo_Buffalo_buffalo_buffalo_buffalo_Buffalo_buffalo
Upvotes: 0
Reputation: 66371
You're mapping (p q)
over the list, so start with figuring out what that is.
Using the subsitution method, you get
(p q)
==> ((lambda (x) (lambda (y) (x (x y)))) q)
==> (lambda (y) (q (q y)))
==> (lambda (y) (q ((lambda (x) (* x x)) y)))
==> (lambda (y) (q (* y y)))
==> (lambda (y) ((lambda (x) (* x x)) (* y y)))
==> (lambda (y) (* (* y y) (* y y)))
so (p q)
is a function that takes a number and squares its square.
Upvotes: 1
Reputation: 1732
Two functions are provided:
(define p (lambda (x) (lambda (y) (x (x y)))))
(define q (lambda (x) (* x x)))
q
is a function which takes a number and squares it.
p
is a function which takes a function x
, and returns another function where x
is applied twice to y
. Please note that in p
, that x
is in the function location of the forms, and has been highlighted in the listing to show this.
The use of x
in both expressions is unfortunately confusing. You can replace any variable in a lambda expression with any other variable, for example function
- this is called alpha-conversion - https://en.wikipedia.org/wiki/Lambda_calculus - and you can change the name of any named function to something more sensible. So, I've renamed q
to square
, the squaring function, and I've renamed p
to do-twice
.
(define do-twice (lambda (function) (lambda (y) (function (function y)))))
(define square (lambda (x) (* x x)))
It then becomes obvious what is happening when you evaluate do-twice square
.
Upvotes: 0