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.
Related
I have a pipeline function that takes an arbitrary number of functions as arguments, it returns a single function helper which contain one argument and this function in turn calls the pipeline function with a single argument iteratively. Here is the code:
def pipeline(*funcs):
def helper(arg):
for func in funcs:
result = func(arg)
arg = result
return result
return helper
And here a test case:
fun = pipeline(lambda x: x * 3, lambda x: x + 1, lambda x: x / 2)
print(fun(3)) #should print 5.0
I was reading on a different question about generators and how they can be used to remember previous state here, and was wondering if I could reframe my current pipeline function to use a generator instead. I need to remember the arg for every func call and currently I'm doing that by storing into a variable, however since generators can remember the last state I was wondering if I could use it instead.
You could (but absolutely shouldn't) create a side-effect based list-comprehension that uses the walrus-operator:
funcs = [lambda x: x * 3, lambda x: x + 1, lambda x: x / 2]
x = 3
[x := f(x) for f in funcs]
print(x)
What makes this even worse than it already is is the fact that if you use a simple generator instead of the list-comprehension the result is different because it doesn't all get executed before the print.
Or you even force it all in one line like this:
print([x := f(x if i>0 else 3) for i, f in enumerate(funcs)][-1])
I think generally a prettier approach would be to just wrap it into a normal for loop:
x = 3
for f in funcs:
x = f(x)
print(x)
I am having trouble understanding the following function.
def make_adder(n):
return lambda x: x + n
plus_2 = make_adder(2)
plus_2(5)
>>> 7
In this function, what does x represent and how does this not result in an error because x is undefined?
The x represents the parameter that the lambda expression receives, this is why it's before the ":".
When you do the plus_2 = make_adder(2) call, the lambda expression substitutes the n with the parameter of the function (2), so now plus_2 equals lambda x: x + 2. When you call plus_2(5) the lambda expression is evaluated, substituting the x with the function parameter (5), so the result is 5 + 2 = 7;
You're defining a function which, given n, returns a function which accepts an argument x and returns x + n. This is called a higher-order function. It doesn't yield an error because you're explicitly returning another function which expects an argument.
Lambda functions are awesome. They allow you to define higher-order functions inline. The general format is lambda args: expression. In this case, x is the argument passed into the lambda function. Because make_adder returns a lambda function, whatever you pass into make_adder is set as n. So when you pass in make_adder(2) you get a lambda function that adds 2 to the argument (x).
Decomposing your original snippet:
def make_adder(n):
return lambda x: x + n
plus_2 = make_adder(2) # returns lambda x: x + 2
plus_2(5) # executes lambda expression, x + 2 with x=5
Starting from scratch:
5 + 2 # 7
plus_two_fn = lambda x: x + 2 # Add 2 when you call plus_two_fn(x)
plus_two_fn(3) # returns 5 (3 + 2)
def plus_num_fn(num):
return lambda x: x + n # Allow you to define plus "any" number
plus_one_fn = plus_num_fn(1) # lambda x: x + 1
plus_one_fn(2) # returns 3 (2 + 1)
In the line below:
plus_2 = make_adder(2)
we're binding the integer object 2 to n.
After that when plus_2 is called using the argument:
plus_2(5)
the integer object 5 would be bind to x when the lambda expression is executed.
This is the runtime execution flow. Since there is no ambiguity or errors in this whole process, the program runs just fine and outputs 7.
Now, to answer your question: the variable x represents whatever value is passed to plus_2() as per your naming.
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
Just for curiosity. Discovered Lambdas a few days ago. I was jus wondering if something like that can be done:
(Tried on the interpret but none of my tries seemed to work)
p = lambda x: (lambda x: x%2)/2
There's no explicit purpose. I just did'nt find a satisfactory answer. I may have misunderstood Lambdas.
You can use an inner lambda to return another function, based on the outer parameters:
mul = lambda x: (lambda y: y * x)
times4 = mul(4)
print times4(2)
You aren't actually calling the inner lambda:
p = lambda x: (lambda x: x%2)(x)/2
Note in Python 2 this example will always return 0 since the remainder from dividing by 2 will be either 0 or 1 and integer-dividing that result by 2 will result in a truncated 0.
(lambda x: x%2) is a function, and dividing a function by 2 doesn't make any sense. You probably want to call it and divide what the value it returned.
I'm trying to do the following, which is a representative example of what my final goal will be:
yu = lambda x: 0
for i in range(0,5):
yu = lambda x: i + yu(x)
Unfortunately, it returns:
RuntimeError: maximum recursion depth exceeded
when I do:
print yu(0)
The print statement should return 10.
What's the correct way to do this?
In the end, you have:
yu = lambda x: i + yu(x)
but yu will be looked up at runtime, not when you constructed the lambda. Do this instead:
for i in range(0,5):
yu = lambda x, yu=yu: i + yu(x)
This does not return 10, though. It returns 20 instead:
>>> yu = lambda x: 0
>>> for i in range(0,5):
... yu = lambda x, yu=yu: i + yu(x)
...
>>> yu(0)
20
because now i is still looked up from the context (and by now the loop has finished so it's 4). Solution? Move i to a keyword argument too:
for i in range(0,5):
yu = lambda x, yu=yu, i=i: i + yu(x)
Now this works:
>>> yu = lambda x: 0
>>> for i in range(0,5):
... yu = lambda x, yu=yu, i=i: i + yu(x)
...
>>> yu(0)
10
Moral of the story? Bind your context properly to the scope of the lambda.
yu = lambda x: i + yu(x)
This makes yu into a function that always calls itself, guaranteeing infinite recursion with no base case.
Why? Well, you've built a closure where yu (and i) are the local variables in the function or module that the for loop is part of. That's not what you want; you want to close over the current values of yu and i, not the outer variables.
I'm not sure why you're even using lambda in the first place. If you want to define a function and give it a name, use def.
Here's an easy solution:
def yu(x): return 0
def make_new_yu(yu, i):
def new_yu(x): return i + yu(x)
return new_yu
for i in range(0, 5):
yu = make_new_yu(yu, i)
By making the wrapping explicit, the correct way to do it becomes the most obvious way to do it.
You can, of course, use a lambda inside make_new_yu without making things more confusing:
def make_new_yu(yu, i):
return lambda x: i + yu(x)
And you can even make the initial definition a lambda if you want. But if you insist on not having any def statements, you need to force the right values into the closure in some way, e.g., by using the default-value trick. That's much easier to get wrong—and harder to read once you've done it.
If you want an intuitive understanding of the difference, without learning the details: a function body defines a new scope. So, defining the function (by lambda or def) inside that function means your closure is from that new scope.
I believe I didn't fully understand your question, but could anyone check if this is what he meant?
I assumed you wouldn't need an iterator to generate a list of digits
yu = lambda x: x[0] + yu(x[1:]) if x!=[] else 0
facto = lambda f: f if f == 0 else f + facto(f-1)
print(facto(4))
Considering the answers you try to sum up 0, 1, 2, 3, 4. If that was right you could use the following lambda expression:
yu = lambda x: x + yu(x+1) if x<4 else x
For yu(0) it delivers 10 as a result. The break condition is the value of x which is required to stay smaller than 4 in order to add up.
Assuming that is what you desired to do, you should leave out the loop for a rather concise statement.
This lambda expression differentiates from the others in resulting in different values (other than 10, when not choosing 0 as the parameter x) depending on the given argument.