Это не проблема ленивого ввода-вывода.Ленивый ввод-вывод - это когда вы читаете ленивую строку из файла, но не оцениваете ее - среда выполнения в этом случае будет откладывать фактическое чтение до тех пор, пока вы не оцените его.
Проблема заключается в том, чтона самом деле вы не делаете IO в allEvents
- вы просто перемещаетесь вокруг значений в IO
функторе .Этими значениями являются IO
сами действия, но это не имеет значения.В частности, a >>= return . f
всегда совпадает с fmap f a
, согласно законам монады.И fmapping в IO не связывает действия.
Эта проблема уже наблюдается в сигнатуре типа: -> IO (Maybe (IO [()]))
говорит, что функция выдает действия IO, которые вы затем могли бы выполнить позже.Но в этом случае вы хотите выполнить все, когда вы выполняете allEvents
.Таким образом, подпись может быть
allEvents :: IO (Maybe [Url]) -> IO ()
(или, возможно, -> IO (Either EventExecError ())
, если вы хотите правильно обработать ошибку).
Это, вероятно, все еще не то, что вы хотите: почему вы принять IO
действие в качестве аргумента?Это означает, что allEvents
сам должен будет выполнить это действие, чтобы сначала получить URL-адреса, прежде чем выполнять какую-либо собственную работу.Это может иметь свои побочные эффекты и давать разные результаты для разных звонков, вы хотите это?
Наверное, нет, так что на самом деле это должно быть
allEvents :: Maybe [Url] -> IO ()
Теперь вы начинаете с простого значения Maybe
, которое вы можете легко сопоставить с шаблоном:
allEvents Nothing = ? -- perhaps simply `return ()`
allEvents (Just urls) = mapM_ doThings urls
Чтобы затем использовать это в своей программе, вам нужно монадически привязать выборку URL квыполнение события:
main :: IO ()
main = do
urlq <- allUrls
allEvents urlq
... или короткое allUrls >>= allEvents
.