Рассмотрим следующую программу Haskell. Я пытаюсь программировать в "поточном стиле", где функции работают на потоках (реализованы здесь просто как списки). Такие вещи, как normalStreamFunc, отлично работают с ленивыми списками. Я могу передать бесконечный список normalStreamFunc и эффективно выйти из другого бесконечного списка, но с функцией, отображаемой на каждое значение. Такие вещи, как effectfulStreamFunc, не работают так хорошо. Действие IO означает, что мне нужно оценить весь список, прежде чем я смогу выделить отдельные значения. Например, вывод программы следующий:
a
b
c
d
"[\"a\",\"b\"]"
но то, что я хочу, - это способ написать effectfulStreamFunc, чтобы программа произвела это:
a
b
"[\"a\",\"b\"]"
оставляя оставшиеся действия неоценимыми. Я могу представить решение, использующее unsafePerformIO, но позвольте сказать, что я снимаю это со стола. Вот программа:
import IO
normalStreamFunc :: [String] -> [String]
normalStreamFunc (x:xs) = reverse(x) : normalStreamFunc xs
effectfulStreamFunc :: [String] -> IO [String]
effectfulStreamFunc [] = return []
effectfulStreamFunc (x:xs) = do
putStrLn x
rest <- effectfulStreamFunc xs
return (reverse(x):rest)
main :: IO ()
main = do
let fns = ["a", "b", "c", "d"]
es <- effectfulStreamFunc fns
print $ show $ take 2 es
Update:
Спасибо всем за полезную и продуманную обратную связь. Я раньше не видел оператора sequence
, о котором полезно узнать. Я думал о (менее элегантном) способе передавать значения IO (String) вместо строк, но для стиля программирования, который имеет ограниченную полезность, поскольку я хочу, чтобы другие функции потока действовали самими строками, а не на действия, которые могут создавать строку. Но, основываясь на мыслях с помощью других ответов, я думаю, я понимаю, почему это вообще неразрешимо. В простом случае, который я представил, я действительно хотел, был оператор sequence
, так как я думал, что упорядочение потока подразумевает упорядочение действий. Фактически, такой порядок не обязательно подразумевается. Это становится яснее для меня, когда я думаю о функции потока, которая принимает два потока в качестве входных данных (например, попарно добавляет два потока). Если оба "входящих" потока выполняются IO, упорядочение этих операций ввода-вывода undefined (если, конечно, мы не определяем его, упорядочивая его самостоятельно в монаде IO). Проблема решена, спасибо вам всем!