Привет, Хабр!
В этой статье я хотел бы рассказать о том, что пришло в Python из функциональных языков программирования. Заинтересовавшихся прошу под кат.
Генераторы списков
Это легко и просто: вместо
l = []
for x in range(10):
if x % 2 == 0:
l.append(x)
мы пишем
l = [x for x in range(10) if x % 2 == 0]
Коротко и понятно.
В Haskell тоже самое буде выглядеть так:
let l = [x | x <- [0..10], x `mod` 2 == 0]
Лямбды
Допустим, мы пишем графический интерфейс и у нас есть функция button(**kwargs), где допустимые именованные аргументы: text — для текста, width — для ширины, height — для высоты и command — для callback-функции:
def callback(event):
print("Button pressed")
button(text="Press me", width=32, height=16, command=callback)
Обратите внимание, насколько маленький у нас callback, неужели его нелзя пропихнуть аргументом? Можно! Нам помогут лямбды:
button(text="Press me", width=32, height=16, command=lambda x: print("Button pressed"))
Чисто и легко!
В Haskell передача функции в качестве аргумента встречается на каждом шагу, например функция map берет функцию и список и возвращает список, к каждому элементу которого была применена эта функция:
map (\x -> x+1) [1..10]
На Python это:
map(lambda x: x+1, [x for x in range(1, 10)])
Правда, в Python нет map.
upd: map есть!
Карринг
Карринг (каррирование) — это когда мы передаем старой функции один или несколько аргументов, чтобы получить новую, которая принимает остальные (спасибо AnutaU за более точное определение). Например: print — это функция (я использую Python 3), у нее есть именованный аргумент end — конец строки, по умолчанию он равен "\n". Я хочу не переходить на новую строку, тогда пишу
print(str, end="")
Давайте сделаем функцию printf, которая не будет переходить на новую строку
def printf(*args, **kwargs):
kwargs["end"] = ""
print(*args, **kwargs)
Коряво, можно и проще:
from functools import partial
printf = partial(print, end = "")
Вот он, карринг — мы говорим, что хотим точно такой же, но с перламутровыми пуговицами функцию print, но чтобы end был равен "". Все просто.
И снова Haskell: у нас есть функция +, которая берет два аргумента, мы говорим:
let plusTwo = (+2)
теперь у меня есть функция, которая прибавляет 2 к единственному аргументу.
У меня все, если вы знаете, что еще есть в Python из функциональщины — прошу в комментарии.
Вопросы и отзывы туда же.
Комментарии (13)
AnutaU
22.08.2017 15:57-1Карринг (каррирование) — это когда мы делаем новую функцию из старой с одним или несколькими аргументами.
Какое-то не очень понятное определение. Каррированная функция — это функция, которая принимает один аргумент, и возвращает другую функцию, которая принимает остальные.
Во многих функциональных языках вообще не существует функций нескольких аргументов, они эмулируются либо с помощью каррирования, либо с помощью кортежей.s2002kir Автор
22.08.2017 16:00Я действительно кривовато объяснил, а насчёт функциональных языков — да так и есть.
playermet
22.08.2017 16:22+6То что в статье названо каррированием, на самом деле является частичным применением.
koldyr
22.08.2017 16:25+1Третий случай — это частичное применение.
Каррирование имеет сигнатуру
curry :: ((a,b)->c)->a->b->c
saw_tooth
22.08.2017 17:28+3А где filter?map?reduce?functool?
Если это обзорная статья, то нужно говорить о всех вещах, а не только об очевидном.
Низачет, в общем то…
Kwent
22.08.2017 17:40Официальная дока и вот эта милая книжка (мне понравилась). А еще на хабре немного было.
kesn
22.08.2017 20:02Ваше «чисто и легко» просто не сработает! stackoverflow.com/questions/2970858/why-doesnt-print-work-in-a-lambda
domix32
24.08.2017 11:18Стоит однако отметить что генераторы списков в Python 2 и 3 называются иначе. В Python 2.7
range
возвращает массив, а не генератор, а для генератора необходимо вызыватьxrange
. В третьей версииxrange
стал простоrange
, а выделение готовых массивов происходит через другие механизмы.
AnutaU