Haskell: Monadic takeWhile?

Mam kilka funkcji napisanych w C, które nazywam z Haskell. Te funkcje powracająIO (CInt). Czasami chcę uruchamiać wszystkie funkcje bez względu na to, co z nich powróci, a to jest łatwe. Ze względu na przykładowy kod jest to ogólna idea tego, co dzieje się obecnie:

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

Dostaję pożądane efekty uboczne i nie dbam o wyniki. Ale teraz muszę przerwać wykonywanie natychmiast po pierwszym elemencie, który nie zwraca pożądanego rezultatu. Powiedzmy, że wartość powrotu 4 lub wyższa wymaga wykonania, aby zatrzymać - a następnie co jachcieć zrobić to:

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

Co daje mi ten błąd:

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

I to ma dla mnie sens - wynik jest nadal zawarty w monadzie IO i nie mogę po prostu porównać dwóch wartości zawartych w monadzie IO. Wiem, że to jest właśnie cel monad - łączenie wyników razem i odrzucanie operacji, gdy spełniony jest pewien warunek - ale czy w tym przypadku jest łatwy sposób na „zamknięcie” monady we / wy, aby przestać wykonywać łańcuch pod warunkiem według mojego wyboru, bez pisania wystąpieniaMonadPlus?

Czy mogę po prostu „odsunąć” wartości odf, w celu podjęcia, chociaż?

Czy to rozwiązanie pasuje do funktorów? Funktorzy jeszcze „nie kliknęli” ze mną, ale mam wrażenie, że to może być dobra sytuacja, by z nich skorzystać.

Aktualizacja:

@sth ma najbliższą odpowiedź na to, czego chcę - w rzeczywistości jest to prawie dokładnie to, do czego dążyłem, ale nadal chciałbym sprawdzić, czy istniejestandard rozwiązanie, które nie jest wyraźnie rekurencyjne - w końcu to Haskell! Patrząc wstecz na to, jak sformułowałem moje pytanie, teraz widzę, że nie byłem wystarczająco jasny o moim pożądanym zachowaniu.

Thef funkcja użyta powyżej dla przykładu była tylko przykładem. Prawdziwe funkcje są napisane w języku C i używane wyłącznie do ich efektów ubocznych. Nie mogę użyć sugestii @ TomamapM_ f (takeWhile (<4) [0..5]) ponieważ nie mam pojęcia, czy dane wejściowe naprawdę spowodują sukces lub niepowodzenie do czasu wykonania.

Tak naprawdę nie zależy mi na zwróconej liście - po prostu chcę wywołać funkcje C, dopóki lista nie zostanie wyczerpana lub pierwsza funkcja C nie zwróci kodu błędu.

W pseudokodzie w stylu C moim zachowaniem byłoby:

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

Tak więc odpowiedź @ sth wykonuje dokładnie to, czego chcę, z wyjątkiem tego, że wyniki mogą (powinny?) Zostać odrzucone. ZAdropWhileM_ funkcja byłaby równoważna moim celom. Dlaczego nie ma takiej funkcji lubtakeWhileM_ w Control.Monad? Widzę, że byłopodobna dyskusja na liście mailingowej, ale wydaje się, że nic z tego nie wyszło.

questionAnswers(5)

yourAnswerToTheQuestion