Haskell: ¿toma monádica mientras?

Tengo algunas funciones escritas en C que llamo de Haskell. Estas funciones vuelvenIO (CInt). A veces quiero ejecutar todas las funciones independientemente de lo que devuelva cualquiera de ellas, y esto es fácil. Para obtener un código de ejemplo, esta es la idea general de lo que está sucediendo actualmente:

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

Tengo los efectos secundarios deseados y no me importan los resultados. Pero ahora necesito detener la ejecución inmediatamente después del primer elemento que no devuelve el resultado deseado. Digamos que un valor de retorno de 4 o superior requiere una ejecución para detenerse, entonces lo que yoquerer hacer es esto:

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

Lo que me da este error:

<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])

Y eso tiene sentido para mí: el resultado todavía está contenido en la mónada IO, y no puedo simplemente comparar dos valores contenidos en la mónada IO. Sé que este es precisamente el propósito de las mónadas: encadenar los resultados y descartar las operaciones cuando se cumple una determinada condición, pero hay una manera fácil de "envolver" la mónada IO en este caso para detener la ejecución de la cadena en una condición De mi elección, sin escribir una instancia deMonadPlus?

¿Puedo simplemente "liberar" los valores def, a los efectos del takeWhile?

¿Es esta una solución donde encajan los funtores? Los funcionalistas todavía no han "activado" conmigo, pero tengo la impresión de que esta podría ser una buena situación para usarlos.

Actualizar:

@sth tiene la respuesta más cercana a lo que quiero, de hecho, eso es casi exactamente lo que buscaba, pero todavía me gustaría ver si hay unaestándar Solución que no es explícitamente recursiva. ¡Esto es Haskell, después de todo! Recordando cómo formulé mi pregunta, ahora puedo ver que no estaba lo suficientemente claro acerca de mi comportamiento deseado.

losf La función que usé anteriormente para un ejemplo fue simplemente un ejemplo. Las funciones reales están escritas en C y se utilizan exclusivamente para sus efectos secundarios. No puedo usar la sugerencia de @Tom demapM_ f (takeWhile (<4) [0..5]) porque no tengo idea de si alguna entrada realmente resultará en éxito o fracaso hasta que se ejecute.

Tampoco me importa la lista devuelta, solo quiero llamar a las funciones C hasta que la lista se agote o la primera función C devuelva un código de falla.

En el pseudocódigo de estilo C, mi comportamiento sería:

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

Entonces, nuevamente, la respuesta de @ sth realiza el comportamiento exacto que quiero, excepto que los resultados pueden (¿deberían?) Ser descartados. UNAdropWhileM_ La función sería equivalente para mis propósitos. ¿Por qué no hay una función como esa otakeWhileM_ en Control.Monad? Veo que habiauna discusión similar en una lista de correo, pero parece que nada ha salido de eso.

Respuestas a la pregunta(5)

Su respuesta a la pregunta