Основная идея заключается в том, что вы пишете код следующим образом:
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
Вы читаете параметры в «основной» функции с помощью действия ввода-вывода, а затем передаете эти параметры в ваши рабочие функции.в качестве дополнительного аргумента.
Проблема с этим стилем заключается в том, что блок параметров должен быть передан каждой маленькой функции, которая должна получить к нему доступ.Это неприятность.Вы обнаружите, что некоторые функции на десять уровней ниже в дереве вызовов теперь нуждаются в некотором параметре времени выполнения, и вам нужно добавить этот параметр времени выполнения в качестве аргумента для всех промежуточных функций.Это известно как tramp data .
Монада "решение" заключается в том, чтобы встроить параметр времени выполнения в Reader Monad и превратить все ваши функции в монадическиедействия.Это избавляет от явного параметра данных tramp, но заменяет его монадическим типом, и под капотом эта монада фактически выполняет вытеснение данных для вас.
Императивный мир решает эту проблему с помощью глобальной переменной.В Haskell вы можете делать то же самое, как это:
parameters = unsafePerformIO readConfigurationParametersSomehow
При первом использовании «параметров» выполняется «readConfigurationParametersSomehow», и с этого момента он ведет себя как постоянное значение, прихотя бы до тех пор, пока ваша программа работает.Это одно из немногих правомерных применений unsafePerformIO.
Однако, если вам понадобится такое решение, вам действительно нужно подумать о своем дизайне.Скорее всего, вы не задумываетесь над обобщением своих функций ниже;если какая-то ранее чистая функция внезапно нуждается в параметре времени выполнения, тогда посмотрите на причину и посмотрите, можете ли вы каким-либо образом использовать функции более высокого порядка.Например:
- Передайте функцию, построенную с использованием параметра, а не самого параметра.
- Пусть рабочая функция внизу возвращает функцию, которая передается вверхбыть составленным с помощью функции на основе параметров на более высоком уровне.
- Выполнить рефакторинг стека вызовов таким образом, чтобы фундаментальные операции выполнялись примитивами более низкого уровня внизу, которые составлены зависимым от параметров способом вверху.
В любом случае будет задействовано