Mam niektóre funkcje napisane w C, które nazywam z Haskell. Funkcje te zwracają IO (CInt)
. Czasami chcę uruchomić wszystkie funkcje, niezależnie od tego, co powróci, i to jest łatwe. Przez wzgląd na przykład kodu, jest to ogólna idea tego, co dzieje się obecnie:Haskell: monadyczne pobieranie?
Prelude> let f x = print x >> return x
Prelude> mapM_ f [0..5]
0
1
2
3
4
5
Prelude>
dostaję moje pożądanych efektów ubocznych, a ja nie dbam o wynikach. Ale teraz muszę zatrzymać wykonywanie natychmiast po pierwszym przedmiocie, który nie zwraca pożądanego wyniku. Powiedzmy, że wartość zwracana 4 lub wyższa wymaga wykonanie zatrzymać - to co Chcę zrobić to w ten sposób:
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 sens ja - wynik wciąż jest zawarty w monadzie IO i nie mogę po prostu porównać dwóch wartości zawartych w monadzie IO. Wiem, że to jest dokładnie cel monad - łączenie wyników razem i odrzucanie operacji, gdy spełniony jest pewien warunek - ale jest tam łatwy sposób na "zawinięcie" monografii IO w tym przypadku, aby zatrzymać wykonywanie łańcucha pod warunkiem z mojego wyboru, bez pisania instancji MonadPlus
?
Czy mogę po prostu "cofnąć" wartości z f
, dla celów czasu trwania?
Czy to jest rozwiązanie, w którym mieszczą się funktory? Funktorzy jeszcze mnie nie "kliknęli", ale mam wrażenie, że to dobra sytuacja, żeby z nich skorzystać.
Aktualizacja:
@sth ma najbliższy odpowiedź na to, co chcę - w rzeczywistości, to niemal dokładnie to, co się dzieje za, ale to wciąż chciał zobaczyć, czy jest tam standardowe rozwiązanie, które nie jest jawnie rekurencyjne - to przecież Haskell! Patrząc wstecz, jak sformułowałem moje pytanie, teraz widzę, że nie byłem wystarczająco jasny o moim pożądanym zachowaniu.
Funkcja f
, której użyłem powyżej dla przykładu, była jedynie przykładem. Prawdziwe funkcje są napisane w języku C i używane wyłącznie dla ich skutków ubocznych. Nie mogę użyć sugestii @ Toma: mapM_ f (takeWhile (<4) [0..5])
, ponieważ nie mam pojęcia, czy jakiekolwiek dane wejściowe rzeczywiście doprowadzą do sukcesu lub niepowodzenia, dopóki nie zostaną wykonane.
Nie zwracam uwagi na zwróconą listę - chcę tylko wywoływać funkcje C, dopóki lista nie zostanie wyczerpana lub pierwsza funkcja C zwróci kod błędu.
W stylu C Pseudokod, moje zachowanie byłoby:
do {
result = function_with_side_effects(input_list[index++]);
} while (result == success && index < max_index);
więc ponownie, odpowiedź @ STH za wykonuje dokładne zachowanie, które chcę, oprócz tego, że wyniki mogą (powinny?) Zostać odrzucone. Funkcja dropWhileM_
byłaby odpowiednia dla moich celów. Dlaczego nie ma takiej funkcji lub takeWhileM_
w Control.Monad? Widzę, że było a similar discussion on a mailing list, ale wydaje się, że nic z tego nie wynika.
To także trochę rozczarowuje, że 'sortBy' nie jest zdefiniowany w terminach' sortByM :: Monad m => (a -> a -> m Ordering) -> [a] -> m [a] '. –