Could someone explain what the output of this expression is and how it is generated. I know I can put this in IDLE and check the output but I want to learn how to do it manually. Specifically, I would like to know how the print statement is executed step by step.
def f(x):
return lambda y: (x, y(x))
def g(y):
return lambda x: x(y)
print(g(2)(f)(lambda x:x+1))
This is all purely functional code (except for print itself), so we can just use substitution to visualize what's going on:
print(g(2)(f)(lambda x:x+1))
# ^^^^
Step 1: Call g with 2, binding g's argument y to 2 ...
def g(y): # y = 2
return lambda x: x(y)
... giving lambda x: x(2).
print((lambda x: x(2))(f)(lambda x:x+1))
# ^^^^^^^^^^^^^^^^^^^
Step 2: Call the lambda function (that was returned from g) with f ...
(lambda x: x(2)) # x = f
# ^^^^
... which in turn calls f with 2 ...
def f(x): # x = 2
return lambda y: (x, y(x))
... giving lambda y: (2, y(2)):
print((lambda y: (2, y(2)))(lambda x:x+1))
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Step 3: Call the lambda function (that was returned from f via the other lambda) with lambda x:x+1 ...
(lambda y: (2, y(2)) # y = lambda x:x+1
# ^^^^
... giving (2, (lambda x:x+1)(2)), which in turn calls the argument lambda function with 2 ...
lambda x:x+1 # x = 2
... giving 3, which is then incorporated into the result of the outer lambda, giving (2, 3):
print((2, 3))
#^^^^^^^^^^^^
This is finally the point at which print is invoked, passing a tuple as argument.
Related
I'm wondering why these 2 pieces of code are different?
This code gives me the answer of 5
curry2 = lambda f: lambda x: lambda y: f(x, y)
m = curry2(add)
m(2)(3)
5
This one gives me the location of my function
def lambda_curry2(func):
return lambda f: lambda x: lambda y: f(x, y)
curry2 = lambda_curry2(add)
add_three = curry2(3)
add_three(5)
The second one isn't using func. You don't need as many lambdas, because func is the function you want to call.
So it should be;
def lambda_curry2(func):
return lambda x: lambda y: func(x, y)
Put another way, your definition of curry2 is equivalent to:
def curry2(f):
return lambda x: lambda y: f(x, y)
In general,
name = lambda <vars>: <expression>
is short for
def name(<vars>):
return <expression>
lambda is usually used when you don't need to name the function (e.g. when you want to pass a simple function as an argument or return it as a value).
So i have a homework question, but I'm not sure why I got it wrong / how it works.
once = lambda f: lambda x: f(x)
twice = lambda f: lambda x: f(f(x))
thrice = lambda f: lambda x: f(f(f(x)))
print(thrice(twice)(once)(lambda x: x + 2)(9))
My ans: 25 -> 8*2 +9
Actual ans: 11 -> 2 + 9
What I was thinking:
thrice -> f(f(f(x))),
let new_x = twice(x)
thrice -> f(f(new_x)),
let new_x2 = twice(new_x)
thrice -> f(new_x2),
let new_thrice = twice(new_x2)
so afterwards I add in the (once) and did
new_thrice(once)(lambda x: x+2)(9)
But answer seems to be that (once) nullifies the earlier thrice(twice) and am lost about. Would be great if someone has an explanation.. Thanks!
I hope this will help you to figure out what is going on!
once = lambda f: lambda x: f(x)
twice = lambda f: lambda x: f(f(x))
thrice = lambda f: lambda x: f(f(f(x)))
# Created this one to help readability.
custom_func = lambda x: x + 2
print("once:", once(custom_func)(9)) # returns value
print("twice:", twice(custom_func)(9)) # returns value
print("thrice:", thrice(custom_func)(9)) # returns value
print("applying all those:", thrice(custom_func)(twice(custom_func)(once(custom_func)(9))))
# This represents the following: (((9 + 2) + 2 + 2) + 2 + 2 + 2)
# each pair of parenthesis mean one function being applied, first once, then twice, then thrice.
# If I've understood correctly you need to achieve 25
# to achieve 25 we need to apply +4 in this result so, which means +2 +2, twice function...
print("Achieving 25:", twice(custom_func)(thrice(custom_func)(twice(custom_func)(once(custom_func)(9)))))
# That is it! Hope it helps.
once(lambda x: x+2) evaluates to a function that applies lambda x: x+2 to its argument. In other words, it's equivalent to lambda x: x+2.
once(once(lambda x: x+2)) evaluates to a function that applies once(lambda x: x+2) to its argument. In other words, it's also equivalent to lambda x: x+2.
once(once(once(lambda x: x+2))) evaluates to a function that applies once(once(lambda x: x+2)) to its argument. In other words, this is also equivalent to lambda x: x+2. This doesn't change no matter how many times you apply once.
thrice(twice)(once) evaluates to a function that applies once to its argument some number of times. (8 times, not that it matters for the analysis.) once doesn't change a function's behavior. No matter how many times you apply once, the final function only applies the underlying function once.
thrice(twice)(once)(lambda x: x + 2) thus evaluates to a function that does the same thing as lambda x: x + 2.
Now, if it had been thrice(twice)(once(lambda x: x + 2)) (note the moved parentheses), then that would have applied thrice(twice) to once(lambda x: x + 2), and the result would be a function that applies lambda x: x + 2 8 times.
I am trying to understand nested lambdas:
f = lambda x, y: y(y(x))
g = lambda x : lambda y: x(y)
print( f(lambda x: x+1, g) (4) )
I was told that this code printed "5". How is this explained, and how should one parse the (4) in the last line?
From my understanding of lambda, if,
h = lambda a, b : a+b
i know that print(h(1,2)) will give 3
as a = 1, b =2, and proceed with a+b = 1+2 =3
f(lambda x: x+1, g) ultimately returns another function. That function is then called with 4 as its argument to produce the final result of 5.
Let h = lambda x: x + 1, because this becomes a mess to trace otherwise.
First, we apply f to h and g.
f(h, g)(4) == (lambda x,y: y(y(x))(h, g)(4)
== g(g(h))(4)
Next, we'll evaluate the inner call to g:
g(g(h))(4) == g((lambda x: lambda y: x(y))(h))(4)
== g(lambda y: h(y))(4)
== g(h)(4)
The last step is an example of eta reduction, to use a term from lambda calculus: a function that applies a second function to an argument is equivalent to the second function itself.
Finally, we evaluate g(h) again the same way, which finally gets us to an expression that doesn't involve passing a function as an argument, and lets us get a final answer.
g(h)(4) == (lambda y: h(y))(4)
== h(4)
== (lambda x: x + 1)(4)
== 4 + 1
== 5
Let's have a go at expanding the logic. First, I'm going to rename some argument names to differentiate your two functions:
f = lambda i, j: j(j(i))
g = lambda x: lambda y: x(y)
Now f(lambda x: x+1, g) is equivalent to:
h = (lambda i, j: j(j(i)))(lambda x: x+1, g)
Here, a function being used as an argument. This is fine, as functions are first-class objects in Python and can be passed around in this way. So evaluating this:
h = g(g(lambda x: x+1))
But g is nothing fancy, it simply takes a function and applies it to an argument. It can be considered an "identity" function with a function as an argument. You can get rid of g altogether. So we have:
h = (lambda x: x+1)
In other words, h just adds one to any input.
h = lambda x: x+1 is a function that returns 1 more than the value passed to it. It is equivalent to:
def h(x):
return x+1
f = lambda x, y: y(y(x)) is a function which takes a value and a function as a pair of arguments and evaluates function(function(value)).
It is equivalent to:
def f(x, y):
return y(y(x))
g = lambda x: lambda y: x(y) is a decorator function that returns a new function based on function passed to it.It is equivalent to:
def g(x):
def new_func(y):
return x(y)
return new_func
the given lambda expressions,
f = lambda x, y: y(y(x))
g = lambda x : lambda y: x(y)
expression to evaluate
f(lambda x: x+1, g) (4)
this reduces to
=> g(g(lambda x: x+1)) (4)
now note that g(g(lambda x: x+1)) returns a function g(lambda x: x+1)
=> g(lambda x: x+1) (4)
now here g(lambda x: x+1) again returns a function (x+1)
=> (x+1) (4)
this evaluates to 4+1 i.e 5
=> 5
I have the following straightforward function in Python 3:
def func(i,j):
return lambda i,j: (i*j)
Here's an example of what this function should do:
IN: func(4,'Hello')
OUT: ('Hello' 'Hello' 'Hello' 'Hello')
However, the actual output is an address in memory where the result is stored. What modification do I need to make?
If you want to return the value of i * j, then go ahead and return it. A lambda means it returns a function that acts as you want it to. Consider this:
def mul(x, y):
return x * y
def func(x, y):
return lambda x, y: x*y
Now let's take a look at a little shell session:
>>> mul(4, 'hello')
'hellohellohellohello'
>>> func(4, 'hello')
<function 'lambda' at ...>
>>> f = func(4, 'hello')
>>> f(4, 'hello')
'hellohellohellohello'
As you can see, when you use lambda, your function returns a function which, in turn, needs to be called. The arguments x and y have no correspondence to the arguments in the lambda function.
Since your expected output is a tuple of x lots of y, use a tuple in your function:
def func(i, j):
return (j,) * i
When assigning a variable to an anonymous function using a one line if statement, the 'else' case does not behave as expected. Instead of assigning the anonymous function listed after the 'else', a different anonymous function is assigned. This function returns the expected anonymous function.
>> fn = lambda x: x if True else lambda x: x*x
>> fn(2)
2
>> fn = lambda x: x if False else lambda x: x*x
>> fn(2)
<function <lambda> at 0x10086dc08>
>> fn('foo')(2)
4
What seems to be happening is that lambda x: x if False else lambda x: x*x as a whole is returned as an anonymous function in the 'else' case. I was able to achieve the desired behavior by using the following:
>> fn = (lambda x: x*x, lambda x: x)[True]
>> fn(2)
2
>> fn = (lambda x: x*x, lambda x: x)[False]
>> fn(2)
4
However, I would still like to get the bottom of this unusual behavior. Any thoughts?
lambda has a weaker binding than the conditional expression. In fact, it has the least operator precedence in the language. From the documentation1:
So, this line:
fn = lambda x: x if True else lambda x: x*x
is actually being interpreted by Python as:
fn = lambda x: (x if True else lambda x: x*x)
To do what you want, you would need to add parenthesis:
fn = (lambda x: x) if True else (lambda x: x*x)
1Note that the table is ordered from least to greatest.