Итак, что-то, что имеет тенденцию быть довольно глобальным, например, журнал или конфигурацию, вы бы предложили поместить в монаду ввода-вывода? Глядя на (правда, очень ограниченный набор) примеров, я прихожу к мысли, что код Haskell имеет тенденцию быть либо чистым (то есть вовсе не монадическим), либо монадой ввода-вывода. Или это заблуждение?
Я считаю это заблуждением, только монада IO не чистая. монады наподобие Write / T / Reader / T / State / T / ST все еще остаются чисто функциональными. Вы можете написать чистую функцию, которая использует любую из этих монад внутри, как в этом совершенно бесполезном примере:
foo :: Int -> Int
foo seed = flip execState seed $ do
modify $ (+) 3
modify $ (+) 4
modify $ (-) 2
Все, что это делает, - это неявно распределять / связывать состояние, то, что вы бы сделали вручную явно, нотация do здесь просто дает вам приятный синтаксический сахар, чтобы он выглядел императивным. Здесь вы не можете выполнять какие-либо действия ввода-вывода, вы не можете вызывать какие-либо внешние функции. Монада ST позволяет вам иметь реальные изменяемые ссылки в локальной области видимости, имея при этом чистый функциональный интерфейс, и вы не можете выполнять какие-либо действия ввода-вывода в нем, он все еще остается чисто функциональным.
Вы не можете избежать некоторых действий ввода-вывода, но вы не хотите возвращаться к вводу-выводу для всего, потому что это то, куда может пойти все, ракеты могут быть запущены, у вас нет контроля. В Haskell есть абстракции для управления эффективными вычислениями с разной степенью безопасности / чистоты, монада ввода-вывода должна быть последним средством (но вы не можете полностью избежать этого).
В вашем примере я думаю, вам следует придерживаться использования преобразователей монад или монад, сделанных на заказ, которые делают то же самое, что и их компоновка с помощью преобразователей. Я никогда не писал настраиваемую монаду (пока), но я довольно часто использовал преобразователи монад (мой собственный код, не на работе), не беспокойтесь о них так сильно, используйте их, и это не так плохо, как вы думаете .
Вы видели главу из Real World Haskell, в которой используются преобразователи монад ?
person
snk_kid
schedule
03.05.2010
newtype
и автоматически создав любые нужные вам экземпляры. - person C. A. McCann   schedule 03.05.2010newtype Foo r a = Foo (ReaderT r (State r) a) deriving (Functor, Monad)
не будет работать, потому что он упоминает r дважды. - person luqui   schedule 04.05.2010IO
в основе, который служил бы ядром приложения, поэтому я избегал проблемы, упомянутой Луки, просто задавая параметры типа, а не параметризуяnewtype
. Обычно стеки заканчивалисьReader
,Error
, каким-тоRandom
илиSupply
и немногоState
, чего бы это ни стоило. - person C. A. McCann   schedule 04.05.2010newtype Foo a = Foo (ErrorT String IO a) deriving (Monad, MonadError)
. Монада получена нормально, MonadError ... нет. (GHC 6.12.1 / Debian x64) - person jrockway   schedule 05.05.2010newtype Foo a = Foo (ErrorT String IO a) deriving (Monad, MonadError String)
, поскольку сообщение об ошибке GHC косвенно предполагает ('MonadError' не имеет арности 1). - person C. A. McCann   schedule 06.05.2010m n a
, какое из n или m находится вверху или внизу стека и что это означает. Поэтому я избегаю преобразователя монад, но это только я. - person mb14   schedule 04.09.2016