6

I came accross the following interview question and have no idea how to solve it:

def cons(a, b):
    def pair(f):
        return f(a, b)
    return pair

Given a pair, e.g cons(6,8) I am requested to return a and b separetely, e.g in this case 6, 8 respectively.

Meaning, for example,

def first(pair):
    pass
    #would return pair's `a` somehow

def second(pair):
    pass
    #would return pair's `b` somehow

How can this be done?

Gulzar
  • 23,452
  • 27
  • 113
  • 201
  • 1
    what do you mean by "to return separately"? – kederrac Aug 12 '19 at 05:39
  • This may help you understand closures better. https://stackoverflow.com/questions/4020419/why-arent-python-nested-functions-called-closures – Deepansh Aug 12 '19 at 05:44
  • so you wan just "a" to be returned, or you want also another function to return the second one? – kederrac Aug 12 '19 at 06:01
  • 1
    @rusu_ro1 I want to understand the concept. It is the same, but I edited again to also have the second one, for completeness. – Gulzar Aug 12 '19 at 06:04

5 Answers5

2

The function cons takes two arguments, a and b, and returns a function that takes one argument, f. The returned function is a closure, since it contains references to a and b which would otherwise be out of scope when cons returns.

The returned function takes a function argument, calls it with a and b, and returns the result.

For example, if you do:

func = cons(6, 8)

Then you can do:

def g(a, b):
    return a

func(g)

This will return 6. Similarly, if you define g to return b, then func would return 8.

Tom Karzes
  • 22,815
  • 2
  • 22
  • 41
2

you can try:

pair = cons(6, 8)

def first(pair):
    return  pair(lambda x, y: x)

def second(pair):
    return  pair(lambda x, y: y)

print(first(pair))
print(second(pair))

# ouput:
# 6
# 8
kederrac
  • 16,819
  • 6
  • 32
  • 55
1

How about:

c = cons(6, 8)
a = c.__closure__[0].cell_contents
b = c.__closure__[1].cell_contents

print(a, b)
Sraw
  • 18,892
  • 11
  • 54
  • 87
1

Create a lambda uses iter(args) to make the args passed into cons iterable. Then, the caller can use next(it) to access individual elements:

def cons(a, b):
    def pair(f):
        return f(a, b)
    return pair

it = cons(6, 8)(lambda *args: iter(args))
print(next(it)) # => 6
print(next(it)) # => 8
ggorlen
  • 44,755
  • 7
  • 76
  • 106
0

If you want an indexed item it is a task for getitem.

from operator import getitem
item0 = cons(6, 8)(lambda *v: getitem(v, 0))
item1 = cons(6, 8)(lambda *v: getitem(v, 1))

or

from operator import getitem
func = cons(6, 8)
item0 = func(lambda *v: getitem(v, 0))
item1 = func(lambda *v: getitem(v, 1))
Matthias
  • 12,873
  • 6
  • 42
  • 48