Co dokładnie oznacza „funkcja częściowa” w programowaniu funkcjonalnym?

55

Według mojego zrozumienia, funkcje częściowe są funkcjami, które otrzymujemy, przekazując do funkcji mniej parametrów niż oczekiwano. Na przykład, jeśli byłoby to bezpośrednio poprawne w Pythonie:

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

W powyższym fragmencie new_functionznajduje się funkcja częściowa. Jednak według Haskell Wiki definicja funkcji częściowej to

Funkcja częściowa to funkcja, która nie jest zdefiniowana dla wszystkich możliwych argumentów określonego typu.

więc moje pytanie brzmi: co dokładnie oznacza „funkcja częściowa”?

Saurabh kukade
źródło
37
Mylisz częściowo zastosowaną funkcję z funkcją częściową .
Willem Van Onsem,
11
Python partialwykonuje częściową aplikację , podczas gdy Haskell robi to automatycznie. Wpis wiki odnosi się do funkcji częściowych , które są terminem z matematyki.
L3viathan
9
Ściśle mówiąc, Haskell nie wykonuje częściowej aplikacji funkcji. Każda funkcja pobiera jeden argument, a aplikacja funkcji stosuje funkcję do pojedynczego argumentu. Curry symuluje to, co uważasz za częściową aplikację w innym języku, poprzez symulację funkcji wielu argumentów. Coś takiego add 3 5nie jest aplikacją jednofunkcyjną. To pierwsze dotyczy add3, aby uzyskać nową funkcję, która następnie jest stosowana do 5.
chepner
W języku C # partialmetoda jest deklaracją do przodu opcjonalnie zaimplementowanej metody prywatnej w innym miejscu w bazie kodu projektu.
Dai,
1
Twój przykład może zostać new_function = functools.partial(add, 1)
uznany

Odpowiedzi:

76

Jesteś tutaj, myląc dwie koncepcje. Częściowo stosowana funkcja [Haskell, encyklopedia] z częściowym funkcji [Haskell, encyklopedia] .

Częściowo zastosowana funkcja to:

Częściowe zastosowanie w Haskell polega na przekazaniu mniej niż pełnej liczby argumentów do funkcji, która pobiera wiele argumentów.

mając na uwadze, że funkcja częściowa rzeczywiście jest funkcją niecałkowitą:

Funkcja częściowa to funkcja, która nie jest zdefiniowana dla wszystkich możliwych argumentów określonego typu.

Willem Van Onsem
źródło
24
To dobra odpowiedź, ale można ją poprawić, dodając przykład częściowej funkcji do samej odpowiedzi.
ApproachingDarknessFish
2
Nie jestem pewien, czy zgadzam się z tą dokładną definicją częściowo zastosowanej funkcji. Funkcje w Haskell zawsze biorą tylko jeden argument, nigdy „wiele argumentów”. Użyłbym definicji „częściowe zastosowanie (częściowe zastosowanie funkcji) w Haskell wymaga podania mniej niż pełnej liczby argumentów potrzebnych do uzyskania wartości, której nie można dalej zastosować do innego argumentu”. (dostosowano stąd )
TerryA
21

Funkcja częściowa (zarówno w kontekście programowania funkcjonalnego, jak i matematyki) jest dokładnie tym, co mówi wiki: funkcja nieokreślona dla wszystkich możliwych argumentów. W kontekście programowania zwykle interpretujemy „nieokreślony” jako jedną z kilku rzeczy, w tym niezdefiniowane zachowanie, wyjątki lub brak wypowiedzenia.

Przykładem funkcji częściowej może być dzielenie liczb całkowitych, które nie jest zdefiniowane, jeśli dzielnik ma wartość 0 (w Haskell zgłosi błąd).

w powyższym fragmencie nowa_funkcja jest funkcją częściową.

Ten kod po prostu spowodowałby błąd w Pythonie, ale gdyby działał tak, jak zamierzałeś, byłby to funkcja całkowita (czyli nie częściowa).

Jak już zauważyli komentatorzy, najprawdopodobniej myślisz o tym, że byłaby to funkcja częściowo zastosowana .

sepp2k
źródło
18

Odpowiedzi wyjaśniają wszystko, dodam tylko jeden przykład w każdym języku:

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

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

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

nie jest to ani funkcja częściowa, ani funkcja curry , to tylko funkcja, której nie podałeś wszystkich argumentów .

Funkcja curry w pythonie powinna wyglądać tak:

partialAdd= lambda x: lambda y: x + y

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

4

i w haskell:

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

plusOne = plus 1

plusOne 4

5

Funkcja częściowa w pythonie:

def first(ls):
    return ls[0]

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

wynik

2

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

I w Haskell, jak pokazał twój link :

head [1,2,3]
3

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

Czym więc jest funkcja całkowita?

Cóż, w zasadzie odwrotnie: jest to funkcja, która będzie działać dla każdego wejścia tego typu. Oto przykład w pythonie:

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

i to działa nawet w przypadku list nieskończonych, jeśli użyjesz małej sztuczki:

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]

I odpowiednik w 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]

Tutaj funkcje nie zawieszają się na zawsze. Koncepcja jest taka sama: dla każdej listy funkcja będzie działać.

Damián Rafael Lattenero
źródło
Warto wspomnieć, że Python obsługuje funkcje częściowe w standardowej bibliotece.
Przywróć Monikę