Haskell: monadische takeWhile?

Ich habe einige Funktionen in C geschrieben, die ich von Haskell aus aufrufe. Diese Funktionen kehren zurückIO (CInt). Manchmal möchte ich alle Funktionen ausführen, unabhängig davon, was sie zurückgeben, und das ist einfach. Beispielcode: Dies ist die allgemeine Vorstellung davon, was gerade passiert:

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

Ich habe die gewünschten Nebenwirkungen und kümmere mich nicht um die Ergebnisse. Aber jetzt muss ich die Ausführung sofort nach dem ersten Element stoppen, das nicht das gewünschte Ergebnis liefert. Nehmen wir an, ein Rückgabewert von 4 oder höher erfordert die Ausführung, um zu stoppen - dann was ichwollen zu tun ist dies:

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

Was gibt mir diesen Fehler:

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

Und das macht für mich Sinn - das Ergebnis ist immer noch in der E / A-Monade enthalten, und ich kann nicht einfach zwei in der E / A-Monade enthaltene Werte vergleichen. Ich weiß, dass dies genau der Zweck von Monaden ist - Verketten von Ergebnissen und Verwerfen von Vorgängen, wenn eine bestimmte Bedingung erfüllt ist -, aber es gibt in diesem Fall eine einfache Möglichkeit, die E / A-Monade "einzuwickeln", um die Ausführung der Kette bei einer Bedingung zu beenden von meiner Wahl, ohne eine Instanz von zu schreibenMonadPlus?

Kann ich einfach die Werte aus "heben"ffür die Zwecke der takeWhile?

Ist dies eine Lösung, bei der Funktoren passen? Functors haben noch nicht mit mir "geklickt", aber ich habe irgendwie den Eindruck, dass dies eine gute Situation sein könnte, um sie zu benutzen.

Aktualisieren:

@sth hat die genaueste Antwort auf meine Wünsche - genau das wollte ich eigentlich, aber ich würde immer noch gerne sehen, ob es eine gibtStandard Lösung, die nicht explizit rekursiv ist - das ist schließlich Haskell! Wenn ich zurückblicke, wie ich meine Frage formuliert habe, sehe ich, dass ich nicht klar genug über mein gewünschtes Verhalten war.

Dasf Die Funktion, die ich oben für ein Beispiel verwendet habe, war nur ein Beispiel. Die reellen Funktionen sind in C geschrieben und werden ausschließlich für ihre Nebenwirkungen verwendet. Ich kann @Toms Vorschlag von nicht verwendenmapM_ f (takeWhile (<4) [0..5]) weil ich keine Ahnung habe, ob eine Eingabe wirklich zum Erfolg oder Misserfolg führt, bis sie ausgeführt wird.

Die zurückgegebene Liste interessiert mich auch nicht wirklich - ich möchte nur die C-Funktionen aufrufen, bis entweder die Liste erschöpft ist oder die erste C-Funktion einen Fehlercode zurückgibt.

In C-Stil Pseudocode wäre mein Verhalten:

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

Die Antwort von @ sth führt also genau das gewünschte Verhalten aus, mit der Ausnahme, dass die Ergebnisse möglicherweise verworfen werden (sollten?). EINdropWhileM_ Funktion wäre für meine Zwecke gleichwertig. Warum gibt es so eine Funktion nicht odertakeWhileM_ in Control.Monad? Ich sehe, dass es das gabeine ähnliche Diskussion auf einer Mailingliste, aber es scheint, dass nichts davon gekommen ist.

Antworten auf die Frage(5)

Ihre Antwort auf die Frage