Используйте аналитику count
:
select name, trip_id,
count(*) over() as cnt
from main
order by name
;
Прочтите Функциональное программирование в двух словах .
У программирования без сохранения состояния есть множество преимуществ, не последним из которых является чрезвычайно многопоточность и одновременность код. Откровенно говоря, изменяемое состояние - враг многопоточного кода. Если значения по умолчанию неизменяемы, программистам не нужно беспокоиться о том, что один поток изменяет значение общего состояния между двумя потоками, поэтому это устраняет целый класс ошибок многопоточности, связанных с условиями гонки. Поскольку нет условий гонки, нет причин для использования блокировок, поэтому неизменяемость устраняет еще один целый класс ошибок, связанных с взаимоблокировками.
Это большая причина того, почему функциональное программирование имеет значение, и, вероятно, лучшая из них для прыжков на поезд функционального программирования.
Чем больше частей вашей программы не имеют состояния, тем больше существует способов соединить части вместе без каких-либо поломок . Сила парадигмы без гражданства заключается не в безгражданстве (или чистоте) как таковом , а в способности, которую она дает вам писать мощные, многоразовые функции и комбинировать их.
Вы можете найдите хорошее руководство с множеством примеров в статье Джона Хьюза Почему функциональное программирование имеет значение (PDF).
Вы будете на кучу более продуктивными, особенно если вы выберете функциональный язык, который также имеет алгебраические типы данных и сопоставление с образцом (Caml, SML, Haskell).
Без состояния очень легко автоматически распараллелить ваш код (поскольку процессоры создаются с все большим количеством ядер, это очень важно).
Многие другие ответы были сосредоточены на производительности (параллелизме) функционального программирования, что, по моему мнению, очень важно. Однако вы специально спросили о продуктивности, например, можете ли вы запрограммировать то же самое быстрее в функциональной парадигме, чем в императивной парадигме.
На самом деле я нахожу (из личного опыта), что программирование на F # соответствует тому, как я думаю лучше , а так проще. Я думаю, это самая большая разница. Я программировал как на F #, так и на C #, и в F # гораздо меньше «борьбы с языком», что мне нравится. Вам не нужно думать о деталях в F #. Вот несколько примеров того, что мне действительно нравится.
Например, несмотря на то, что F # статически типизирован (все типы разрешаются во время компиляции), вывод типа определяет, какие типы у вас есть, поэтому вам не нужно это говорить. И если он не может этого понять, он автоматически делает вашу функцию / класс / все что угодно универсальным. Так что вам никогда не придется писать что-то общее, все происходит автоматически. Я считаю, что это означает, что я трачу больше времени на размышления о проблеме и меньше на то, как ее реализовать. Фактически, всякий раз, когда я возвращаюсь к C #, я обнаруживаю, что очень скучаю по этому выводу типа, вы никогда не поймете, насколько это отвлекает, пока вам больше не нужно это делать.
Также в F # вместо написания циклов вы функции вызова. Это небольшое изменение, но существенное, потому что вам больше не нужно думать о конструкции цикла. Например, вот фрагмент кода, который может пройти и что-то сопоставить (не могу вспомнить, что именно, это из головоломки Эйлера проекта):
let matchingFactors =
factors
|> Seq.filter (fun x -> largestPalindrome % x = 0)
|> Seq.map (fun x -> (x, largestPalindrome / x))
Я понимаю, что сделать фильтр, а затем карту (то есть преобразование каждого элемента) в C # было бы довольно просто, но вы должны думать на более низком уровне. В частности, вам нужно будет написать сам цикл и иметь свой собственный явный оператор if и тому подобное. С тех пор, как я изучил F #, я понял, что мне легче кодировать функциональным способом, где, если вы хотите фильтровать, вы пишете «filter», а если вы хотите сопоставить, вы пишете «map» вместо реализации каждая из деталей.
Мне также нравится оператор |>, который, как мне кажется, отделяет F # от ocaml и, возможно, других функциональных языков. Это оператор конвейера, он позволяет вам «перенаправить» вывод одного выражения на ввод другого выражения. Это заставляет код больше следовать тому, как я думаю. Как и в приведенном выше фрагменте кода, это ' говорит: «Возьмите последовательность факторов, отфильтруйте ее, затем сопоставьте». Это очень высокий уровень мышления, которого нельзя достичь в императивных языках программирования, потому что вы так заняты написанием операторов цикла и if. Это единственное, чего мне больше всего не хватает, когда я перехожу на другой язык.
В общем, хотя я могу программировать и на C #, и на F #, мне легче использовать F #, потому что вы можете думать на более высоком уровне. Я бы сказал, что, поскольку мелкие детали удалены из функционального программирования (по крайней мере, в F #), я более продуктивен.
Изменить : Я видел в одном из комментариев, который вы просили привести пример «состояния». "на функциональном языке программирования. F # можно написать императивно, поэтому вот прямой пример того, как можно иметь изменяемое состояние в F #:
let mutable x = 5
for i in 1..10 do
x <- x + i
Обдумайте все сложные ошибки, на отладку которых вы потратили много времени.
Итак, сколько из этих ошибок произошло из-за «непреднамеренного взаимодействия» между двумя отдельными компонентами программы? (Почти все ошибки потоковой передачи имеют такую форму: гонки, связанные с записью общих данных, взаимоблокировки, ... Кроме того, часто встречаются библиотеки, которые оказывают неожиданное влияние на глобальное состояние или читают / записывают реестр / среду и т. Д.) Я полагаю, что по крайней мере 1 из 3 «серьезных ошибок» попадает в эта категория.
Теперь, если вы переключитесь на программирование без сохранения состояния / неизменяемость / чистое программирование, все эти ошибки исчезнут. Вместо этого вы сталкиваетесь с некоторыми новыми проблемами (например, когда вы действительно хотите, чтобы различные модули взаимодействовали с окружающей средой), но в таком языке, как Haskell, эти взаимодействия явно воплощаются в системе типов, что означает, что вы можете просто посмотрите на тип функции и объясните, какое взаимодействие она может иметь с остальной частью программы.
Это большая победа от «неизменяемости» IMO. В идеальном мире мы все разрабатывали бы потрясающие API, и даже когда все было изменчиво, эффекты будут локальными и хорошо задокументированными, а «неожиданные» взаимодействия будут сведены к минимуму. В реальном мире существует множество API-интерфейсов, которые различными способами взаимодействуют с глобальным состоянием, и они являются источником самых пагубных ошибок. Стремление к безгражданству означает стремление избавиться от непреднамеренных / неявных / закулисных взаимодействий между компонентами.
Одно из преимуществ функций без сохранения состояния состоит в том, что они позволяют выполнять предварительное вычисление или кэширование возвращаемых значений функции. Даже некоторые компиляторы C позволяют явно отмечать функции как не имеющие состояния, чтобы улучшить их оптимизацию. Как отмечали многие другие, функции без сохранения состояния намного проще распараллеливать.
Но эффективность - не единственная проблема. Чистую функцию легче тестировать и отлаживать, поскольку все, что влияет на нее, явно указано. А при программировании на функциональном языке у человека появляется привычка делать как можно меньше функций «грязными» (с вводом-выводом и т. Д.). Такое разделение содержимого с отслеживанием состояния - хороший способ разрабатывать программы даже на не очень функциональных языках.
Функциональные языки могут занять некоторое время, чтобы «освоиться», и это трудно объяснить тому, кто не знал т прошел через этот процесс. Но большинство людей, которые настаивают достаточно долго, наконец понимают, что суета того стоит, даже если в конечном итоге они не будут использовать функциональные языки в достаточной степени.
Я написал сообщение только на эту тему некоторое время назад: О важности чистоты .