O que exatamente se entende por "função parcial" na programação funcional?

55

De acordo com meu entendimento, funções parciais são funções que obtemos ao passar menos parâmetros para uma função do que o esperado. Por exemplo, se isso fosse diretamente válido em Python:

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

No trecho de código acima, new_functioné uma função parcial. No entanto, de acordo com o Wiki de Haskell , a definição de função parcial é

Uma função parcial é uma função que não está definida para todos os argumentos possíveis do tipo especificado.

então, minha pergunta é: o que exatamente se entende por "função parcial"?

Saurabh kukade
fonte
37
Você está confundindo uma função parcialmente aplicada com uma função parcial .
Willem Van Onsem 11/11/19
11
O Python partialrealiza aplicação parcial , enquanto o Haskell faz isso automaticamente. A entrada wiki refere-se a funções parciais , que é um termo da matemática.
L3viathan #
9
Estritamente falando, Haskell não faz aplicação de função parcial. Toda função usa um argumento e o aplicativo de função aplica uma função a um único argumento. O curry simula o que você consideraria uma aplicação parcial em outro idioma, simulando funções de múltiplos argumentos em primeiro lugar. Algo como add 3 5não é um aplicativo de função única. Este primeiro aplica-se adda 3 para obter uma nova função, que é então aplicada a 5.
chepner
E em C #, um partialmétodo é uma declaração direta de um método privado opcionalmente implementado em outra parte da base de código do projeto.
Dai
11
Seu exemplo pode ser validado:new_function = functools.partial(add, 1)
wjandrea 12/12/19

Respostas:

76

Você está aqui confundindo dois conceitos. Uma função parcialmente aplicada [haskell-wiki] com uma função parcial [haskell-wiki] .

Uma função parcialmente aplicada é:

A aplicação parcial no Haskell envolve passar menos do que o número total de argumentos para uma função que recebe vários argumentos.

considerando que uma função parcial é de fato uma função não total:

Uma função parcial é uma função que não está definida para todos os argumentos possíveis do tipo especificado.

Willem Van Onsem
fonte
24
Essa é uma boa resposta, mas poderia ser aprimorada adicionando um exemplo de função parcial à própria resposta.
ApproachingDarknessFish
2
Não tenho certeza se concordo com essa definição exata de uma função parcialmente aplicada. As funções no Haskell sempre levam apenas um argumento, nunca "múltiplos argumentos". Eu usaria a definição "aplicação parcial (aplicação parcial de funções) em Haskell envolve fornecer menos do que o número total de argumentos necessários para obter um valor que não pode ser mais aplicado a outro argumento". (adaptado daqui )
TerryA
21

Uma função parcial (tanto no contexto da programação funcional quanto da matemática) é exatamente o que o wiki diz: uma função não definida para todos os seus argumentos possíveis. No contexto da programação, geralmente interpretamos "não definido" como uma das várias coisas, incluindo comportamento indefinido, exceções ou não-encerramento.

Um exemplo de uma função parcial seria a divisão inteira, que não é definida se o divisor for 0 (em Haskell, ocorrerá um erro).

no snippet acima, new_function é uma função parcial.

Esse código simplesmente causaria um erro no Python, mas se funcionasse como você pretendia, seria uma função total (ou seja, não parcial).

Como os comentaristas já apontaram, é mais provável que você pense no fato de que seria uma função parcialmente aplicada .

sepp2k
fonte
18

As respostas explicam tudo, vou apenas adicionar um exemplo em 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'

isso não é uma função parcial nem uma função ao curry , é apenas uma função que você não forneceu todos os seus argumentos .

Uma função ao curry em python deve ser assim:

partialAdd= lambda x: lambda y: x + y

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

4

e em haskell:

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

plusOne = plus 1

plusOne 4

5

Uma função parcial em python:

def first(ls):
    return ls[0]

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

resultado

2

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

E em Haskell, como o seu link apareceu:

head [1,2,3]
3

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

Então, o que é uma função total?

Bem, basicamente o oposto: esta é uma função que funcionará para qualquer entrada desse tipo. Aqui está um exemplo em python:

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

e isso funciona mesmo para listas infinitas, se você usar um pequeno truque:

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]

E o equivalente em 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]

Aqui as funções não ficam para sempre. O conceito é o mesmo: para cada lista a função funcionará.

Damián Rafael Lattenero
fonte
Vale ressaltar que o python tem suporte para funções parciais na biblioteca padrão.
Reintegrar Monica em