Ну, это функционально, но у него нет (последовательного) стиля. «Проблема» заключается в большом разнообразии синтаксисов, используемых для этих выражений.
- вызов функции выполняется с обычной префиксной нотацией
f(arg)
- для получения подмассива используется специальный синтаксис
arr[n?:m?]
вместо функции slice(n,m)
set
- это совершенно другой тип, но он используется промежуточным образом, потому что наборы имеют некоторое поведения, которое мы хотим - то, что мы хотим, это «уникальные» элементы в итерируемом и т. Д. наша функция должна называться unique
. Если мы осуществим unique
с использованием set
, это нормально, но это не забота читателя, чей разум свободен от таких отвлекающих факторов
x.lower()
- это динамический вызов с lower
в инфиксной позиции. Сравните с префиксом позиции lower(x)
. То же самое относится к s.replace(pat,rep)
против replace(s, pat, rep)
map
и filter
однако имеют функциональный интерфейс map(f,iter)
и filter(f,iter)
Но при написании программы, подобной той, которой вы поделились, в некотором роде упускается самая сильная и универсальная черта функционального стиля: функция. Да, функциональное программирование - это также составление красивых цепочек выражений, но не за счет читабельности! Если читаемость начинает ухудшаться, сделайте это лучше с помощью функции: D
Рассмотрим эту программу, которая использует равномерный функциональный стиль. Это все еще обычная программа на Python.
def program (word = '', clip_length = 5, input = ''):
make_words = \
compose ( lower
, partial (replace, '_', ' ')
)
process = \
compose ( partial (map, make_words)
, partial (filter, lambda x: x != word)
, unique
, partial (take, clip_length)
)
return process (input)
print (program ('b', 4, 'A_a_a_B_b_b_c_c_c_d_e'))
# ['d', ' ', 'e', 'a']
# Note, your output may vary. More on this later.
А теперь зависимости. Каждая функция работает исключительно со своими аргументами и возвращает выходные данные.
def partial (f, *xs):
return lambda *ys: f (*xs, *ys)
def compose (f = None, *fs):
def comp (x):
if f is None:
return x
else:
return compose (*fs) (f (x))
return comp
def take (n = 0, xs = []):
return xs [:n]
def lower (s = ''):
return s .lower ()
def replace (pat = '', rep = '', s = ''):
return s .replace (pat, rep)
def unique (iter):
return list (set (iter))
На самом деле, этот вопрос не мог создать лучшую сцену для некоторых из этих пунктов. Я собираюсь вернуться к выбору set
, который использовался в исходном вопросе (и в программе выше), потому что существует огромная проблема: если вы повторно запустите нашу программу несколько раз, мы получим другой выход. Проще говоря, у нас нет ссылочной прозрачности . Это потому, что наборы Python неупорядочены, и когда мы конвертируем из упорядоченного списка в набор, а затем обратно в список, не гарантируется, что мы всегда будем получать одни и те же элементы.
Использование set
таким способом показывает хорошую интуицию о том, как решить уникальную проблему, используя существующие языковые функции, но мы хотим восстановить прозрачность ссылок. В нашей программе выше мы четко закодировали наше намерение получать входные уникальные элементы, вызывая для него функцию unique
.
# deterministic implementation of unique
def unique (iter):
result = list ()
seen = set ()
for x in iter:
if x not in seen:
seen .add (x)
result .append (x)
return result
Теперь, когда мы запускаем нашу программу, мы всегда получаем один и тот же результат
print (program ('b', 4, 'A_a_a_B_b_b_c_c_c_d_e'))
# ['a', ' ', 'c', 'd']
# always the same output now
Это подводит меня к другому вопросу. Поскольку мы абстрагировали unique
в его собственную функцию, нам автоматически предоставляется область действия для определения его поведения. Я решил использовать императивный стиль в реализации unique
, но это нормально, так как это все еще чистая функция и потребитель функции не может отличить. Вы можете придумать 100 других реализаций unique
, если program
работает, это не имеет значения.
Функциональное программирование - это около функций . Язык твой, чтобы приручить. Это все еще обычная программа на Python.
def fwd (x):
return lambda k: fwd (k (x))
def program (word = '', clip_length = 5, input = ''):
make_words = \
compose ( lower
, partial (replace, '_', ' ')
)
fwd (input) \
(partial (map, make_words)) \
(partial (filter, lambda x: x != word)) \
(unique) \
(partial (take, clip_length)) \
(print)
program ('b', 4, 'A_a_a_B_b_b_c_c_c_d_e')
# ['a', ' ', 'c', 'd']
Нажмите и поэкспериментируйте с этой программой на repl.it