Reputation: 21
I was looking at this question:
cons(a, b)
constructs a pair, and car(pair)
and cdr(pair)
returns the first and last element of that pair. For example, car(cons(3, 4))
returns 3, and cdr(cons(3, 4))
returns 4.
Given this implementation of cons:
def cons(a, b):
def pair(f):
return f(a,b)
return pair
Implement car and cdr.
I recognised the lambda expression, but I'm still unsure of how it works. The answer is given as:
def car(f):
z = lambda x, y: x
return f(z)
def cdr(f):
z = lambda x, y: y
return f(z)
If f is the function object, isn't passing z to f calling lambda f : f(a,b)
, where z has 2 arguments but the other lambda only has 1 argument?
How does this solution work?
Upvotes: 1
Views: 118
Reputation: 6601
Let's evaluate car(cons(3, 4))
.
cons(3, 4)
a = 3
b = 4
def pair(f):
return f(3, 4)
return pair
So right now we have car(pair)
, where pair
is:
def pair(f):
return f(3, 4)
car(pair)
Let's see what happens in car
:
f = pair
z = lambda x, y: x
return f(z)
So the last statement can be actually read as:
return pair(z)
or
return pair(lambda x, y: y)
Let's rewrite z as a regular function for the sake of simplicity:
def z(x, y):
return x
return pair(z)
Now we run pair
with z
as parameter.
Remember, pair
is defined as:
def f(n):
return n(3, 4)
So n = z, and we should return:
z(3, 4)
What z
does is actually "return the first parameter".
And... Here you have it :)
Upvotes: 0
Reputation: 531948
You have to recognize how a pair is represented. A pair consists of three things: a first element, a second element, and a function. Most importantly, the two elements are not accessible "directly" (though see below): you can only get to them via the third member of the pair. That function takes another function, and returns the result of applying that function to the two "hidden" elements.
car
takes the pair function and applies it to a function that returns the first of its two arguments.
cdr
takes the pair function and applies it to a function which returns the second of its two arguments.
You can trace this as follows, made easier if you rewrite cons = lambda a, b: lambda f: f(a, b)
:
car(cons(3, 5)) == cons(3, 5)(lambda x, y: x)
== (lambda a, b: lambda f: f(a, b))(3, 5)(lambda x, y: x)
== (lambda f: f(3, 5))(lambda x, y: x)
== (lambda x, y: x)(3, 5)
== 3
cdr(cons(3, 5)) == cons(3, 5)(lambda x, y: y)
== (lambda a, b: lambda f: f(a, b))(3, 5)(lambda x, y: y)
== (lambda f: f(3, 5))(lambda x, y: y)
== (lambda x, y: y)(3, 5)
== 5
cons(3, 5)
essentially stores the values 3 and 5 in the __closure__
attribute of the pair
function it creates.
>>> p1 = cons(3, 5)
>>> p1.__closure__[0].cell_contents
3
>>> p1.__closure__[1].cell_contents
5
Upvotes: 1