Comments 19
Согласен, нет таких проблем, для решения которых было бы необходимо функциональное программирование. Просто некоторые задачи при функциональном подходе решаются более элегантно, что ли. Например, данные при анализе часто приходится прогонять через несколько функций, и генераторы списков не выглядят красивым решением. Да и if/else и словари — не такие гибкие и удобные инструменты, как паттерн-матчинг.
Мой код для обработки данных зачастую выглядит как-то так:
x_train = np.vstack(list(map(lambda x: x.reshape(1, w, h, 3), map(preprocess, map(np.load, map(lambda e: e.filename, protocol))))))
И по количеству закрывающих скобочек стремится к коду на лиспе. Поэтому я очень часто мечтаю о функциональном языке, компилируемом в питон. Автор, большое спасибо. Хочется побольше статей с примерами применения и, в особенности, использования в нём математических пакетов, таких как numpy
например.
На самом деле, писать про использование математических пакетов в Coconut нечего, потому что используются они точно так же, как в питоне. То есть, можно написать вот так:
from operator import attrgetter
import numpy as np
x_train = protocol |> map$(np.reshape$(?, 1, w, h, 3) .. preprocess .. np.load .. attrgetter('filename')) |> list |> np.vstack
и получится рабочий код, который вы можете запустить из интерпретатора или компилировать в питоновский код, эквивалентный вашему примеру (если я правильно его распарсил, конечно). Единственная проблема, которую я тут заметил — нельзя пайпы переносить по строкам без \, но это мелочи и поправимо.
Да-да, совсем как в OCaml, только без строгой типизации (язык-то у нас динамический)
Если быть до конца честным, то Python 3 — строготипизированный, хоть и динамический)
-rw------- 1 u0_a209 u0_a209 25 Feb 16 20:07 coco.coco
-rw------- 1 u0_a209 u0_a209 24K Feb 16 20:08 coco.py
25 байт привет мир превратилис в 25К.
Я, конечно, понимаю. Но все-же :)
Ну да, Coconut компилируется в предположении, что на машине, где его будут запускать, есть только чистый Python. Поэтому в выходном файле оказывается довольно много функций и классов, которые лежат мёртвым кодом. С другой стороны, рантайм питона 3.6 весит 100+ МБ, так что лишних 25К на проект вряд ли кого-то будет волновать)
В примере
sum([n**2 for n in lst])
создаётся целый новый ненужный список с квадратами элементов исходного. Это может быть проблемой, если список большой. Избежать этого можно, написав просто
sum(n**2 for n in lst)
Такой вариант допускает, к тому же, ленивые вычисления, например
all(f() for f in fun_lst) # Выполняет функции до тех пор, пока очередная не вернёт False
all([f() for f in fun_lst]) # Выполнит все функции из списка
Ну и в общем случае, если нужно поработать с элементами коллекции, а не с коллекцией в целом, часто бывает удобно привязать к ней итератор
it = iter(lst)
...
next(it)
Замерил время на возведение в квадрат 100К целых чисел. В среднем, получились такие результаты: Coconut — 87 мс, циклы — 79 мс, генератор списка — 78 мс. Так что язык, скорее всего, немного медленнее питона.
Как раз понадобилось немного посчитать и рылся в справочниках.
(reduce + (map (fn [x] (* x x)) (range 1 6)))
Возможно есть более элегентные способы, которые я не учел, это просто сразу в голове было.
Змея и кокос