Я пишу программу, которая читает из списка файлов. Каждый файл либо содержит ссылку на следующий файл, либо отмечает, что это конец цепочки.
Поскольку я новичок в Haskell, мне показалось, что идиоматический способ справиться с этим - это ленивый список возможных файлов для этой цели, у меня есть
getFirstFile :: String -> DataFile
getNextFile :: Maybe DataFile -> Maybe DataFile
loadFiles :: String -> [Maybe DataFile]
loadFiles = iterate getNextFile . Just . getFirstFile
getFiles :: String -> [DataFile]
getFiles = map fromJust . takeWhile isJust . loadFiles
Пока все хорошо. Единственная проблема заключается в том, что, поскольку getFirstFile и getNextFile должны открывать файлы, мне нужно, чтобы их результаты были в монаде ввода-вывода. Это дает модифицированную форму
getFirstFile :: String -> IO DataFile
getNextFile :: Maybe DataFile -> IO (Maybe DataFile)
loadFiles :: String -> [IO Maybe DataFile]
loadFiles = iterate (getNextFile =<<) . Just . getFirstFile
getFiles :: String -> IO [DataFile]
getFiles = liftM (map fromJust . takeWhile isJust) . sequence . loadFiles
. Проблема в том, что, поскольку итерация возвращает бесконечный список, последовательность становится бесконечным циклом. Я не знаю, что делать дальше. Есть ли более ленивая форма последовательности, которая не затронет все элементы списка? Должен ли я перенастроить карту и takeWhile, чтобы работать внутри монады ввода-вывода для каждого элемента списка? Или мне нужно отбросить весь процесс бесконечного списка и написать рекурсивную функцию для завершения списка вручную?