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”?


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.


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 .


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


Warto wspomnieć, że Python obsługuje funkcje częściowe w standardowej bibliotece.
Przywróć Monikę
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.