Why is this different? Currying/Higher Order Functions - python

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).

Related

Function composition with just lambdas in python

Is there a way to do the following in just one line with lambdas in python?
squared = lambda x : x**2
cubed = lambda x : x**3
squareCubed = lambda x : squared(cubed(x))
without using any helper functions or reduce.
print(squareCubed(2)) # > 64
Sure, you can do something like:
squareCube = (lambda f, g: lambda x: f(g(x)))(lambda x: x**2, lambda x: x**3)
But why do this?
In any case, you shouldn't be assigning the result of lambda to a variable if you are following the official PEP8 style guide. What is wrong with:
def square(x):
return x**2
def cube(x):
return x**3
def compose(f, g):
return lambda x: f(g(x))
square_cube = compose(square, cube)
Is much more readable.
If you want to hard code it:
squareCube = lambda x: (x**3)**2
But generically:
compose = lambda f, g: lambda x: f(g(x))
squareCube = compose(lambda x: x**2, lambda x: x**3)
Or, in one line:
squareCube = (lambda f, g: lambda x: f(g(x)))(lambda x: x**2, lambda x: x**3)
squareCubed = lambda x : (x**3)**2
print(squareCubed(2)) # gives 64

Kernel restarts when calling self defined function which adds together lambda functions

I've tried to define a function that adds several lambda functions together.
When I call the function the kernel crashes and restarts with no further error messages.
def add_lambdas(function_list):
f = lambda x, y: None
for function in function_list:
f = lambda x, y: f(x, y) + function(x, y)
return f
f1 = lambda x, y: x + y
f2 = lambda x, y: x**2 - 2*y
f3 = lambda x, y: f1(x,y) + f2(x,y)
f4 = add_lambdas([f1,f2])
For example, when I call f3(2,3) all is well, but when I call f4(2,3) the kernel crashes and restarts. For f3 I do the adding of f1 and f2 manually, but for f4 I pass them through the function add_lambdas().
This is the output:
In[5]: f3(2,3)
Out[5]: 3
In[6]: f4(2,3)
Restarting kernel...
Obviously something is wrong with my defined function, but I cant figure out what it is. Any thoughts? Thank you!
I believe the problem is that you're defining f as a recursive function, which I don't think is what you want. You can try this instead:
def add_lambdas(function_list):
return lambda x, y: sum(f(x, y) for f in function_list)
You are getting a stack overflow. The problem is that there is only a single variable f and a single variable function in add_lambdas. When you write:
f = lambda x, y: f(x, y) + function(x, y)
you are just assigning a new value to the variable f, but the variable f inside the definition is also that new value. This is the stack overflow. In addition, the variable function will be left with the last value in the list. There is no reason for it to copy the value.
If instead you write:
f = lambda x, y, f=f, function=function: f(x, y) + function(x, y),
you're telling Python to assign f and function to new variables, (with the same name) and to use those new variables inside the lambda. Changes made to the other variables are immaterial
You'll discover a different error in your code. The first line needs to be
f = lambda x, y: 0 since otherwise you're adding an integer to None.
Note that #josemz is the simpler solution if you're just planning on adding things. If you want to learn to use lambdas within other lambdas, you need to make sure variables are bound correctly.

Python Lambda function variable ordering

If I state a lambda function like this:
someLambdaFunction = lambda x,y: x+x**2+y
can I reverse the ordering of that lambda to say
someOtherLambdaFunction = lambda y,x: x+x**2+y
without rewriting the whole lambda function? Just switch the arguments?
Yes, you can do something like this:
someLambdaFunction = lambda x,y: x+x**2+y
someOtherLambdaFunction = lambda y, x: someLambdaFunction(x, y)
Basically, reuse the original someLambdaFunction
You can write a general function that swaps the first two arguments of another function:
def swap2(func):
""" Swap the first two arguments of a function """
def wrapped(x, y, *args, **kwargs):
return func(y, x, *args, **kwargs)
return wrapped
f = lambda x,y: x+x**2+y
f_swapped= swap2(f)
assert f(3, 4) == f_swapped(4, 3)
This works because functions are just regular Python objects, that can be passed around just like integers, strings, etc.
By the way, there is almost never a reason to write something = lambda .... Use def something(...) instead.

How to read or interpret Lambda in Lambda

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

How is the output of this Python expression generated?

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.

Categories

Resources