функциональная эффективность программирования против императива - PullRequest
0 голосов
/ 11 июня 2018

Я новичок в функциональном программировании, и я просто столкнулся с чем-то, и мне было интересно, есть ли способ обойти это.

Предположим, у меня есть

myArray = [
  { a : 1 }
  { a : 4 }
  { a : 5 }
  { a : 6 }
  { a : 7 }
  { a : 8 }
]

Допустим, мне нужновыполнять статистические операции над этим набором данных, например

const median = myArray[ Math.ceil( myArray.length / 2 ) ]['a'] // Math.ceil .. Side Effect?
const fiveOrMore = myArray.filter( value => value.a >= 5 )
const lessThanFive = myArray.filter( value => value.a < 5 )

Некоторые произвольные примеры.Проблема с этим на данный момент состоит в том, что с увеличением количества статистических операций, которые мне нужно сделать, эффективность снижается.

С императивным стилем я мог бы делать все в ONE for loop.Это неправильный подход к функциональному программированию, который я использую, или это компромисс самой парадигмы функционального программирования?

Ответы [ 4 ]

0 голосов
/ 22 августа 2019

Один из моих девизов:

«Мне все равно, как быстро я могу вычислить неправильный ответ.»

Я мог бы попытаться написать несколько супер-быстрый код, но это риск, если мой код трудно понять и, следовательно, легко вводить ошибки / трудно обнаружить ошибки.Если код не является сверхкритическим для скорости выполнения, я выбираю подход, который позволяет наиболее легко выразить то, что я пытаюсь сделать: иногда функциональный подход может сделать ваше намерение очень ясным, в то время как в других ситуациях императив более уместен.

Как только у меня есть код, который работает и проходит набор модульных тестов, я могу переписать его в поисках большей скорости, если это необходимо.

В общем, поэтому я наслаждаюсьСвифт в настоящее время - у меня есть как функциональные, так и императивные варианты.О, и я знаю, что это не чистый функционал, но с моей инженерной, а не компьютерной наукой, это достаточно близко!; -)

0 голосов
/ 12 июня 2018

С функциональным стилем вы могли бы сделать это за один раз.Просто имейте функцию, которая проверяет элемент ниже, и аккумулятор будет представлять собой структуру с двумя списками, в которые вы добавляете элементы.

Если вы думаете о передаче списка через ряд функций более высокого порядка, то вы можете уменьшить накладные расходы с помощью Trancducers , который в основном работает как отдельные map, filter, но без списковмежду операциями.

Есть потоков , которые используют ленивую оценку, если, возможно, вы не будете использовать все элементы в своем результате.

И есть генераторы .По сути, вы можете сделать несколько циклов for и использовать ỳield для «возврата» значения, и вы можете объединить их в цепочку, поскольку все генераторы могут быть повторены с for of.Также здесь вы можете остановить, когда у вас есть достаточно данных.

Так что для всего этого есть свои плюсы и минусы.Производительность, если вы все равно рассчитываете все элементы с использованием генераторов и потоков, будет немного перегружена.Преобразователи, возможно, являются лучшим вариантом, который дает возможность компоновки с небольшим составлением списка, но цикл, конечно, будет быстрее.

Тестирование легче с функциональными реализациями, и вы можете тестировать отдельные этапы изолированно.Один очень большой цикл, который управляет всем приложением, часто трудно отладить.Это также происходит, когда у вас есть один reduce, который просто переписывает один цикл в функциональном стиле.

0 голосов
/ 12 июня 2018

Вы можете втиснуть вещи в один цикл в функциональном или императивном стиле.В обоих стилях это ухудшает читабельность.В обоих стилях ваш компилятор может выполнить цикл слияния , чтобы исключить дополнительный цикл.Кроме того, один цикл не всегда быстрее, и компилятор сможет распознать ситуации, когда слияние подходит лучше, чем это легко могут сделать люди.

Как указывал Сильвестер, функциональное программирование имеет много методов, позволяющих писатьциклы отдельно, но выполняйте их вместе.Функциональный стиль также проще явно распараллеливать на несколько потоков.

Также часто есть библиотечные функции, которые уже выполняют то, что вы хотите в одном цикле, и они являются более описательными и более краткими.Например, две последние строки можно сделать с помощью раздела :

_.partition(myArray, x => x['a'] < 5)
0 голосов
/ 11 июня 2018

Это, конечно, менее производительный.И хит производительности является компромиссом стиля, который вы выбрали.

Можно утверждать, что это не имеет большого значения, поскольку временная сложность составляет O(n), единственное отличиеконстанта .Я бы сказал, убедитесь, что вы тестируете свое приложение.Если он медленный - пришло время оптимизировать определенные блоки кода.

Преждевременная оптимизация - это зло.Во многих случаях императивный код работает быстрее или намного быстрее, намного быстрее, чем функциональный, и в зависимости от ситуации вы можете или не можете согласиться с этим.

Кроме того, существуют различные методы дляулучшить производительность.Вы не обязательно хотите изменить стиль.Скажем, в некоторых случаях памятка может резко повысить скорость работы функции, сохраняя при этом функциональность кода.Просто думай нестандартно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...