Пост чисто философский
Периодическое чтение кусков кода, написанных при обострении хаскеля головного мозга, выработало у меня четкую ассоциацию: функциональный стиль - это нечитаемо. Точнее стиль с множеством map/filter/zip. Вот немного облагороженный пример такого кода (автор считает, что с кодом все ок):
Без подсветки синтаксисаsome_res = ", ".join(
map(str,
filter(None,
map(lambda x: getattr(obj.zip, x, None),
['a', 'b', 'c', 'd']))))
Без переписывания в многострочный вариант ориентироваться в нем вообще сложно:
Без подсветки синтаксисаattrs = ['a', 'b', 'c', 'd']
attr_vals = map(lambda x: getattr(obj.zip, x, None), attrs)
non_none_attrs = filter(None, attr_vals)
some_res = ", ".join(map(str, non_none_attrs))
Этот вариант читается лучше уже потому, что понизилась концентрация логики, и добавились переменные, имена которых служат документацией промежуточным результатам. Но, IMO, это не главные причины.
Первом меня на эту мысль натолкнуло наблюдение за девушкой, которая только начал учить питон и не программировала серьезно до этого. У нее вызывало затруднение определить какие параметры относятся к какой функции даже в достаточно простых выражениях, например:
Без подсветки синтаксисаx = some_func1(a, b, some_func2(c, d), e)
Понятно, что со временем это прошло, но осадок остался - в выражения где много вложенных вызовов и скобок сложно быстро соотнести параметры, функции и удерживать это в голове, пока его анализируешь. Если код не форматирован построчно, как пример выше, то совсем тяжело.
Следующий случай - это функциональный стиль в скале. Его чтение у меня не вызывает того чувства трясины, какое вызывал аналогичный код в python/haskell. Тот же пример на 'скалапитоне' выглядел бы так:
Без подсветки синтаксисаsome_res = ['a', 'b', 'c', 'd'].map(getattr(obj.zip, _, None))\
.filter(None).map(str).join(",")
Если отвлечься от более удобной формы записи лямбды, то он все равно читается гораздо проще. Мне кажется дело в том, что он читается линейно слева направо, а не "вообще изнутри наружу, но местами слева направо", как читается код в питоне.
Это относится скорее не к функциональному стилю, а к процедурный vs ООП, но именно функциональный стиль провоцирует избавление от переменных и написание множества вложенных вызовов функций. Он как лакмусовая бумажка вскрывает плохую масштабируемость читаемости процедурных выражений:
Без подсветки синтаксисаa(x, b(c(), 1, 4), 'd')
# vs
c().b(1, 4).a(x, 'd')
К сожалению питон чаще всего не позволяет писать сцепленными методами, поскольку бОльщая часть методов возвращает None вместо self (а именно все, которые модифицируют объект на месте), а map/filter - функции, а не методы.
Итого я для себя сменил идею с "функциональный код нечитаем" на "функциональный код, написанный в процедурном стиле, нечитаем".
Ссылки:ananthakumaran.in/2010/03/29/scala-underscore-magic.html
Исходники этого и других постов со скриптами лежат тут - github.com/koder-ua. При использовании их, пожалуйста, ссылайтесь на koder-ua.blogspot.com.
1 comment:
Post a Comment