¿Qué se entiende exactamente por "función parcial" en la programación funcional?

55

Según tengo entendido, las funciones parciales son funciones que obtenemos al pasar menos parámetros a una función de lo esperado. Por ejemplo, si esto fuera directamente válido en Python:

>>> def add(x,y):
...    return x+y
... 
>>> new_function = add(1)
>>> new_function(2)
3

En el fragmento anterior, new_functiones una función parcial. Sin embargo, de acuerdo con Haskell Wiki , la definición de función parcial es

Una función parcial es una función que no está definida para todos los argumentos posibles del tipo especificado.

Entonces, mi pregunta es: ¿qué se entiende exactamente por "función parcial"?

Saurabh kukade
fuente
37
Está confundiendo una función parcialmente aplicada con una función parcial .
Willem Van Onsem
11
Python partialrealiza una aplicación parcial , mientras que Haskell lo hace automáticamente. La entrada wiki se refiere a funciones parciales , que es un término de las matemáticas.
L3viathan
99
Estrictamente hablando, Haskell no realiza la aplicación de funciones parciales. Cada función toma un argumento, y la aplicación de la función aplica una función a un solo argumento. Curry simula lo que pensarías como una aplicación parcial en otro idioma al simular funciones de argumentos múltiples en primer lugar. Algo así como add 3 5no es una aplicación de función única. Esto se aplica primero adda 3 para obtener una nueva función, que luego se aplica a 5.
chepner
Y en C #, un partialmétodo es una declaración directa de un método privado opcionalmente implementado en otra parte de la base de código del proyecto.
Dai
1
Su ejemplo podría hacerse válido:new_function = functools.partial(add, 1)
wjandrea

Respuestas:

76

Estás aquí confundiendo dos conceptos. Una función parcialmente aplicada [haskell-wiki] con una función parcial [haskell-wiki] .

Una función parcialmente aplicada es:

La aplicación parcial en Haskell implica pasar menos del número total de argumentos a una función que toma múltiples argumentos.

mientras que una función parcial es una función no total:

Una función parcial es una función que no está definida para todos los argumentos posibles del tipo especificado.

Willem Van Onsem
fuente
24
Esta es una buena respuesta, pero podría mejorarse agregando un ejemplo de una función parcial a la respuesta misma.
Acercarse a
2
No estoy seguro de estar de acuerdo con esa definición exacta de una función parcialmente aplicada. Las funciones en Haskell siempre toman solo un argumento, nunca "argumentos múltiples". Usaría la definición "la aplicación parcial (la aplicación parcial de funciones) en Haskell implica el suministro de menos del número total de argumentos necesarios para obtener un valor que no puede aplicarse más a otro argumento". (Adaptado de aquí )
TerryA
21

Una función parcial (tanto en el contexto de la programación funcional como de las matemáticas) es exactamente lo que dice el wiki: una función no definida para todos sus posibles argumentos. En el contexto de la programación, generalmente interpretamos "no definido" como una de varias cosas, incluido el comportamiento indefinido, las excepciones o la no terminación.

Un ejemplo de una función parcial sería la división de enteros, que no se define si el divisor es 0 (en Haskell arrojará un error).

en el fragmento anterior new_function es una función parcial.

Ese código simplemente causaría un error en Python, pero si funcionara como lo esperaba, sería una función total (es decir, no parcial).

Como los comentadores ya señalaron, lo más probable es que pienses en el hecho de que sería una función parcialmente aplicada .

sepp2k
fuente
18

Las respuestas explican todo, solo agregaré un ejemplo en cada idioma:

def add(x,y):
    return x+y

f = add(1)
print(f(3))

    f = add(1)
TypeError: add() missing 1 required positional argument: 'y'

Esta no es una función parcial ni una función currificada , es solo una función que no dio todos sus argumentos .

Una función curry en python debería ser así:

partialAdd= lambda x: lambda y: x + y

plusOne = partialAdd(1)
print(plusOne(3))

4

y en haskell:

plus :: Int -> Int -> Int
plus x y = x + y

plusOne = plus 1

plusOne 4

5

Una función parcial en python:

def first(ls):
    return ls[0]

print(first([2,4,5]))
print(first([]))

salida

2

print(first([]))
  File "main.py", line 2, in first
    return ls[0]
IndexError: list index out of range

Y en Haskell, como apareció su enlace :

head [1,2,3]
3

head []
*** Exception: Prelude.head: empty list

Entonces, ¿qué es una función total?

Bueno, básicamente lo contrario: esta es una función que funcionará para cualquier entrada de ese tipo. Aquí hay un ejemplo en python:

def addElem(xs, x):
  xs.append(x)
  return xs

y esto funciona incluso para listas infinitas, si usas un pequeño truco:

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]

Y el equivalente en 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]

Aquí las funciones no se cuelgan para siempre. El concepto es el mismo: para cada lista la función funcionará.

Damián Rafael Lattenero
fuente
Vale la pena mencionar que python tiene soporte para funciones parciales en la biblioteca estándar.
Restablece a Mónica el