Что именно подразумевается под «частичной функцией» в функциональном программировании?


55

Насколько я понимаю, частичные функции - это функции, которые мы получаем, передавая в функцию меньше параметров, чем ожидалось. Например, если это было правильно в Python:

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

В приведенном выше фрагменте, new_functionэто частичная функция. Однако, согласно Haskell Wiki , определение частичной функции

Частичная функция - это функция, которая не определена для всех возможных аргументов указанного типа.

Итак, мой вопрос: что именно подразумевается под «частичной функцией»?


37
Вы путаете частично примененную функцию с частичной функцией.
Виллем Ван Онсем

11
Python partialвыполняет частичное применение , тогда как Haskell делает это автоматически. Запись в вики относится к частичным функциям , что является термином из математики.
L3viathan

9
Строго говоря, Haskell не выполняет частичное применение функции. Каждая функция принимает один аргумент, а приложение-функция применяет функцию к одному аргументу. Каррирование имитирует то, что вы считаете частичным применением на другом языке, в первую очередь имитируя функции с несколькими аргументами. Нечто подобное add 3 5не является единственным приложением функции. Это сначала относится addк 3, чтобы получить новую функцию, которая затем применяется к 5.
chepner

А в C # partialметод является предварительным объявлением необязательно реализованного частного метода в другом месте кодовой базы проекта.
Дай

1
Ваш пример может быть приведен в действие:new_function = functools.partial(add, 1)
wjandrea

Ответы:


76

Вы здесь путаете две концепции. Частично применяются функция [Haskell-вика] с частичной функцией [Haskell-вика] .

Частично примененная функция:

Частичное применение в Haskell включает передачу функции, которая принимает несколько аргументов, меньше полного числа аргументов.

тогда как частичная функция действительно является неполной функцией:

Частичная функция - это функция, которая не определена для всех возможных аргументов указанного типа.


24
Это хороший ответ, но его можно улучшить, добавив пример частичной функции к самому ответу.
Приближается к

2
Я не уверен, что согласен с этим точным определением частично примененной функции. Функции в Haskell всегда принимают только один аргумент, а не «множественные аргументы». Я бы использовал определение «частичное применение (частичное применение функций) в Haskell, включающее предоставление меньшего, чем полное количество аргументов, необходимого для получения значения, которое не может быть далее применено к другому аргументу». (адаптировано отсюда )
TerryA

21

Частичная функция (как в контексте функционального программирования, так и математики) - это именно то, что говорит вики: функция, не определенная для всех возможных аргументов. В контексте программирования мы обычно интерпретируем «не определено» как одну из нескольких вещей, включая неопределенное поведение, исключения или отсутствие завершения.

Примером частичной функции может служить целочисленное деление, которое не определяется, если делитель равен 0 (в Хаскеле это приведет к ошибке).

в приведенном выше фрагменте new_function является частичной функцией.

Этот код просто вызвал бы ошибку в Python, но если бы он работал так, как вы хотели, это была бы полная (то есть не частичная) функция.

Как уже отмечали комментаторы, вы, скорее всего, думаете о том, что это будет частично примененная функция.


18

Ответы объясняют все, я просто добавлю один пример на каждом языке:

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

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

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

это не частичная функция и не функция карри , это только функция, которую вы не предоставили всем своим аргументам .

Функция карри в Python должна быть такой:

partialAdd= lambda x: lambda y: x + y

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

4

и в хаскеле:

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

plusOne = plus 1

plusOne 4

5

Частичная функция в Python:

def first(ls):
    return ls[0]

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

вывод

2

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

А в Хаскеле, как показала твоя ссылка :

head [1,2,3]
3

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

Так что же такое общая функция?

Ну, в основном наоборот: это функция, которая будет работать для любого ввода этого типа. Вот пример в Python:

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

и это работает даже для бесконечных списков, если вы используете небольшой трюк:

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]

И эквивалент в 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]

Здесь функции не зависают вечно. Концепция одинакова: для каждого списка функция будет работать.


Стоит отметить, что в стандартной библиотеке Python есть поддержка частичных функций .
Восстановить Монику
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.