Haskell: монадический захват?

У меня есть некоторые функции, написанные на C, которые я вызываю из Haskell. Эти функции возвращаютIO (CInt), Иногда я хочу запустить все функции независимо от того, что из них возвращает, и это легко. Для примера кода это общая идея того, что происходит в настоящее время:

Prelude> let f x = print x >> return x
Prelude> mapM_ f [0..5]
0
1
2
3
4
5
Prelude>

Я получаю желаемые побочные эффекты, и мне плевать на результаты. Но теперь мне нужно остановить выполнение сразу после первого элемента, который не возвращает желаемый результат. Допустим, возвращаемое значение 4 или выше требует остановки выполнения - то, что яwant сделать это:

Prelude> takeWhile (<4) $ mapM f [0..5]

Что дает мне эту ошибку:

<interactive>:1:22:
    Couldn't match expected type `[b]' against inferred type `IO a'
    In the first argument of `mapM', namely `f'
    In the second argument of `($)', namely `mapM f ([0 .. 5])'
    In the expression: takeWhile (< 4) $ mapM f ([0 .. 5])

И это имеет смысл для меня - результат все еще содержится в монаде ввода-вывода, и я не могу просто сравнить два значения, содержащиеся в монаде ввода-вывода. Я знаю, что именно в этом и заключается цель монад - объединение результатов в цепочку и отбрасывание операций при выполнении определенного условия - но есть ли простой способ «обернуть» монада IO в этом случае, чтобы прекратить выполнение цепочки при условии моего выбора, без написания экземпляраMonadPlus?

Могу ли я просто "снять" значения изf, для целей takeWhile?

Это решение для функторов? Функторы не "щелкнули" со мной еще, но у меня вроде есть впечатление, что это может быть хорошая ситуация, чтобы использовать их.

Update:

У @sth есть самый близкий ответ на то, что я хочу - на самом деле, это почти то же, что и я, но я все еще хотел бы увидеть, есть лиstandard решение, которое не является явно рекурсивным - это ведь Haskell! Оглядываясь назад на то, как я сформулировал свой вопрос, теперь я вижу, что не достаточно ясно о своем желаемом поведении.

f Функция, которую я использовал выше для примера, была просто примером. Реальные функции написаны на C и используются исключительно для их побочных эффектов. Я не могу использовать предложение Тома оmapM_ f (takeWhile (<4) [0..5]) потому что я понятия не имею, приведет ли какой-либо ввод к успеху или неудаче, пока не будет выполнен.

На самом деле меня не волнует возвращаемый список - я просто хочу вызывать функции C, пока список не будет исчерпан или первая функция C не вернет код ошибки.

В псевдокоде в стиле C мое поведение будет следующим:

do {
    result = function_with_side_effects(input_list[index++]);
} while (result == success && index < max_index);

Итак, еще раз, ответ @ sth выполняет точное поведение, которое я хочу, за исключением того, что результаты могут (должны?) Быть отброшены.dropWhileM_ Функция будет эквивалентна для моих целей. Почему нет такой функции илиtakeWhileM_ в Control.Monad? Я вижу, что там былоаналогичное обсуждение в списке рассылки, но, похоже, ничего не вышло.

Ответы на вопрос(5)

Ваш ответ на вопрос