According to my understanding, partial functions are functions that we get by passing fewer parameters to a function than expected. For example, if this were directly valid in Python:
>>> def add(x,y):
... return x+y
...
>>> new_function = add(1)
>>> new_function(2)
3
In the snippet above, new_function
is a partial function. However, according to the Haskell Wiki, the definition of partial function is
A partial function is a function that is not defined for all possible arguments of the specified type.
so, my question is: what exactly is meant by "partial function"?
Partials are basically functions that return functions with some already predefined arguments and need some arguments to be completed. Let's say you have a function with several arguments to be set, but you don't want to set the majority of arguments over and over again because you need it more than once.
Another example of a partial function is given by y = x + 1 x2 − 3x + 2 , assuming that both the input and output domains are R. This partial function “blows up” for x = 1 and x = 2, its value is “infinity” (= ∞), which is not an element of R. So, the domain of f is R − {1,2}.
A partial function allows us to call a second function with fixed values in certain arguments. For instance, we may have a function that computes an exponentiation. Then, we may need to create a new function that assigns a fixed value to either the base or the exponent.
Currying is when you define the function. Partial Application is when you call the function. Application is math-speak for calling a function. Partial application requires calling a curried function and getting a function as the return type.
You are here confusing two concepts. A partially applied function [haskell-wiki] with a partial function [haskell-wiki].
A partially applied function is:
Partial application in Haskell involves passing less than the full number of arguments to a function that takes multiple arguments.
whereas a partial function indeed is a non-total function:
A partial function is a function that is not defined for all possible arguments of the specified type.
A partial function (both in the context of functional programming and mathematics) is exactly what the wiki says: a function not defined for all of its possible arguments. In the context of programming, we usually interpret "not defined" as one of several things, including undefined behaviour, exceptions or non-termination.
An example of a partial function would be integer division, which is not defined if the divisor is 0 (in Haskell it will throw an error).
in above snippet new_function is partial function.
That code would simply cause an error in Python, but if it worked as you intended, it would be a total (meaning not partial) function.
As commentors already pointed out, you're most likely thinking of the fact that it'd be a partially applied function.
The answers explain all, I will just add one example in each language:
def add(x,y):
return x+y
f = add(1)
print(f(3))
f = add(1)
TypeError: add() missing 1 required positional argument: 'y'
this is neither a partial function nor a curried function, this is only a function that you didn't gave all its arguments.
A curried function in python should be like this:
partialAdd= lambda x: lambda y: x + y
plusOne = partialAdd(1)
print(plusOne(3))
4
and in haskell:
plus :: Int -> Int -> Int
plus x y = x + y
plusOne = plus 1
plusOne 4
5
A partial function in python:
def first(ls):
return ls[0]
print(first([2,4,5]))
print(first([]))
output
2
print(first([]))
File "main.py", line 2, in first
return ls[0]
IndexError: list index out of range
And in Haskell, as your link showed up:
head [1,2,3]
3
head []
*** Exception: Prelude.head: empty list
So what is a total function?
Well, basically the opposite: this is a function that will work for any input of that type. Here is an example in python:
def addElem(xs, x):
xs.append(x)
return xs
and this works even for infinite lists, if you use a little trick:
def infiniList():
count = 0
ls = []
while True:
yield ls
count += 1
ls.append(count)
ls = infiniList()
for i in range(5):
rs = next(ls)
print(rs, addElem(rs,6))
[1, 2, 3, 4]
[1, 2, 3, 4, 5] [1, 2, 3, 4, 5]
And the equivalent in Haskell:
addElem :: a -> [a] -> [a]
addElem x xs = x : xs
addElem 3 (take 10 [1..])
=> [3,1,2,3,4,5,6,7,8,9,10]
Here the functions doesn't hang forever. The concept is the same: for every list the function will work.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With