#haskell #monads
#haskell #монады
Вопрос:
Цитата отсюда:http://www.haskell.org/haskellwiki/Global_variables
Если у вас есть глобальная среда, из которой считываются различные функции (и вы могли бы, например, инициализировать из файла конфигурации), то вам следует передать это в качестве параметра своим функциям (после того, как, скорее всего, настроили это в своем «основном» действии). Если явная передача параметров вас раздражает, вы можете «скрыть» это с помощью монады.
Сейчас я пишу что-то, для чего нужен доступ к параметрам конфигурации, и мне интересно, может ли кто-нибудь указать мне на учебное пособие или любой другой ресурс, который описывает, как монады можно использовать для этой цели. Извините, если этот вопрос глупый, я только начинаю разбираться в монадах. Сейчас читаю руководство Майка Вайнера по ним.
Комментарии:
1. Для начала вы ищете монаду reader. Но сначала потребуется некоторый ввод-вывод для получения среды.
Ответ №1:
Основная идея заключается в том, что вы пишете код, подобный этому:
main = do
parameters <- readConfigurationParametersSomehow
forever $ do
myData <- readUserInput
putStrLn $ bigComplicatedFunction myData parameters
bigComplicatedFunction d params = someFunction params x y z
where x = function1 params d
y = function2 params x d
z = function3 params y
Вы считываете параметры в функции «main» с помощью действия ввода-вывода, а затем передаете эти параметры в свои рабочие функции в качестве дополнительного аргумента.
Проблема с этим стилем заключается в том, что блок параметров приходится передавать каждой маленькой функции, которой требуется к нему доступ. Это неприятность. Вы обнаруживаете, что некоторой функции на десять уровней ниже в дереве вызовов теперь требуется некоторый параметр времени выполнения, и вы должны добавить этот параметр времени выполнения в качестве аргумента ко всем промежуточным функциям. Это известно как данные tramp.
«Решение» монады заключается в том, чтобы встроить параметр времени выполнения в монаду чтения и преобразовать все ваши функции в монадические действия. Это избавляет от явного параметра tramp data, но заменяет его монадическим типом, и под капотом эта монада фактически выполняет обработку данных за вас.
Императивный мир решает эту проблему с помощью глобальной переменной. В Haskell вы можете вроде как сделать то же самое следующим образом:
parameters = unsafePerformIO readConfigurationParametersSomehow
При первом использовании «parameters» выполняется «readConfigurationParametersSomehow», и с этого момента он ведет себя как постоянное значение, по крайней мере, до тех пор, пока ваша программа запущена. Это одно из немногих правильных применений unsafePerformIO.
Однако, если вы обнаружите, что вам нужно такое решение, тогда вам действительно нужно подумать о своем дизайне. Скорее всего, вы недостаточно усердно думаете об обобщении ваших функций ниже; если какой-то ранее чистой функции внезапно понадобится параметр времени выполнения, тогда посмотрите на причину и посмотрите, можете ли вы каким-то образом использовать функции более высокого порядка. Например:
- Передайте функцию, созданную с использованием параметра, а не сам параметр.
- Должна ли рабочая функция внизу возвращать функцию в результате, которая передается для составления с функцией на основе параметров на более высоком уровне.
- Реорганизуйте свой стек вызовов таким образом, чтобы основные операции выполнялись примитивами более низкого уровня внизу, которые составлены зависящим от параметров образом вверху.
Любой способ будет включать