Функциональные циклы в Python
Замена циклов на выражения так же проста, как и замена условных блоков. 'for' может быть впрямую переведено в map(). Так же, как и с условным выполнением, нам понадобится упростить блок утверждений до одного вызова функции (мы близки к тому, чтобы научиться делать это в общем случае):
- #---------- Функциональный цикл 'for' в Python ----------#
for e in lst: func(e) # цикл на утверждении 'for'
map(func,lst) # цикл, основанный на map()
Кстати, похожая техника применяется для реализации последовательного выполнения программы, используя функциональный подход. Т.е., императивное программирование по большей части состоит из утверждений, требующих "сделать это, затем сделать то, затем сделать что-то еще". 'map()' позволяет это выразить так:
- #----- Функциональное последовательное выполнение в Python ----------#
# создадим вспомогательную функцию вызова функции
do_it = lambda f: f()
# Пусть f1, f2, f3 (etc) - функции, выполняющие полезные действия
map(do_it, [f1,f2,f3]) # последовательное выполнение, реализованное на map()
В общем случае, вся главная программа может быть вызовом 'map()' со списком функций, которые надо последовательно вызвать, чтобы выполнить программу. Еще одно удобное свойство функций как объектов - то, что вы можете поместить их в список.
Перевести 'while' впрямую немного сложнее, но вполне получается :
- #-------- Функциональный цикл 'while' в Python ----------#
# Обычный (основаный на утверждении 'while') цикл
while <cond>:
<pre-suite>
if <break_condition>:
break
else:
<suite>
# Рекурсивный цикл в функциональном стиле
def while_block():
<pre-suite>
if <break_condition>:
return 1
else:
<suite>
return 0
while_FP = lambda: (<cond> and while_block()) or while_FP()
while_FP()
Наш вариант 'while' все еще требует функцию while_block(), которая сама по себе может содержать не только выражения, но и утверждения (statements).
Но мы могли бы продолжить дальнейшее исключение утверждений в этой функции (как, например, замену блока 'if/else' в вышеописанном шаблоне на короткозамкнутое выражение). К тому же, обычная проверка на месте <cond> (наподобие 'while myvar==7') вряд ли окажется полезной, поскольку тело цикла (в представленном виде) не может изменить какие-либо переменные (хотя глобальные переменные могут быть изменены в while_block()). Один из способов применить более полезное условие - заставить while_block() возвращать более осмысленное значение и сравнивать его с условием завершения. Стоит взглянуть на реальный пример исключения утверждений:
- #---------- Функциональный цикл 'echo' в Python ------------#
# Императивная версия "echo()"
def echo_IMP():
while 1:
x = raw_input("IMP -- ")
if x == 'quit':
break
else
print x
echo_IMP()
# Служебная функция, реализующая "тождество с побочным эффектом"
def monadic_print(x):
print x
return x
# FP версия "echo()"
echo_FP = lambda: monadic_print(raw_input("FP -- "))=='quit' or echo_FP()
echo_FP()
Мы достигли того, что выразили небольшую программу, включающую ввод/вывод, циклы и условия в виде чистого выражения с рекурсией (фактически - в виде функционального объекта, который при необходимости может быть передан куда угодно). Мы все еще используем служебную функцию monadic_print(), но эта функция совершенно общая и может использоваться в любых функциональных выражениях , которые мы создадим позже (это однократные затраты). Заметьте, что любое выражение, содержащее monadic_print(x) вычисляется так же, как если бы оно содержало просто x.В FP (в частности, в Haskell) есть понятие "монады" для функции, которая "не делает ничего, и вызывает побочный эффект при выполнении".