Глобальное состояние в функциональном программировании (F #) - PullRequest
0 голосов
/ 18 октября 2019

Я хочу вычислить некоторые функции, которые зависят от некоторых переменных (конкретных данных, для которых я запускаю код) и глобальных переменных, которые вряд ли будут изменены, но я хочу оставить их настраиваемыми пользователем. Просто для пояснения на примере, предположим, что я хочу объявить следующую функцию:

let multiplyByGain x =
   x * gain

Где бы вы объявили усиление, будучи глобальным постоянным для всего проекта. В отдельный модуль с константами? Это связало бы модуль с этим кодом, хотя. Или вы бы использовали карри версию:

let multiblyByGain x gain =
   x * gain

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

В моей конкретной проблеме это становится более громоздким, потому что и x, и усиление - это массивы, которые должны иметь одинаковую длину, предположим, мне нужно сделать Array.zip, например: какова лучшая практика с точки зрения функционального проектированияОбращаться к глобальной константе, как усиление, в общем виде?

PS: Я нашел этот старый пост введите здесь описание ссылки , но решает только конкретную проблему.

1 Ответ

3 голосов
/ 18 октября 2019

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

Упрощение. Использование модуля, представляющего gain в качестве глобального значения, который имеет некоторый код инициализации для чтения конфигурации, кажется хорошим значением по умолчаниюподход в F #. Если это изменяется очень редко (скажем, до того, как вы запустите все вычисления), тогда мутация не вызовет никаких проблем. Вам просто нужно быть осторожным, чтобы избежать изменения значений, пока некоторые вычисления еще выполняются. Я думаю, что большинство программистов на F # склонны относиться к этому довольно прагматично, и это кажется самым легким для начала.

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

Функциональное программирование. Некоторые функцииязыковые сообщества (особенно Haskell и, иногда, Scala) более строгие в отношении государства. Чисто функциональным способом сохранения состояния было бы использование монад (либо монады читателя, либо некоторой свободной структуры монад). Это делает ваш код намного более сложным (как концептуально, так и с точки зрения дополнительных синтаксических издержек), но это чисто функциональное решение, которое устраняет состояние. В F # такой подход еще более громоздок, поэтому он не очень распространен.

...