Szukam funkcji, która zasadniczo jest podobna do mapM
na liście - wykonuje serię monadycznych akcji, przyjmując każdą wartość na liście jako parametr - a każda funkcja monadyczna zwraca m (Maybe b)
. Chcę jednak, aby zatrzymał się po pierwszym parametrze, który powoduje, że funkcja zwraca wartość Just
, a nie wykonuje więcej po tym i zwraca tę wartość.wdrażanie "findM" w Haskell?
Cóż, to chyba łatwiej będzie po prostu pokazać podpis typu:
findM :: (Monad m) => (a -> m (Maybe b)) -> [a] -> m (Maybe b)
gdzie b jest pierwszą wartość Just
. Maybe
w wyniku pochodzi z find
(w przypadku pustej listy itp.) I nie ma nic wspólnego z Maybe
zwróconym przez funkcję Monadic.
Nie mogę tego wdrożyć z prostym zastosowaniem funkcji bibliotecznych. Mógłbym użyć
findM f xs = fmap (fmap fromJust . find isJust) $ mapM f xs
która będzie działać, ale ja testowałem to i wydaje się, że wszystko z monadycznych czynności wykonywane są przed wywołaniem find
, więc nie mogę polegać na lenistwo tutaj.
ghci> findM (\x -> print x >> return (Just x)) [1,2,3]
1
2
3
-- returning IO (Just 1)
Jaki jest najlepszy sposób realizacji tej funkcji, która nie będzie wykonywać monadycznych działań po pierwszym "sprawiedliwym" zwrocie? Coś, co zrobić:
ghci> findM (\x -> print x >> return (Just x)) [1,2,3]
1
-- returning IO (Just 1)
lub nawet najlepiej,
ghci> findM (\x -> print x >> return (Just x)) [1..]
1
-- returning IO (Just 1)
Mam nadzieję, że jest to odpowiedź, która nie korzysta z wyraźną rekurencji i są kompozycje funkcji bibliotecznych jeśli to możliwe? A może nawet bez punktu? jeden?
Hah! Wygląda na to, że mieliśmy dokładnie ten sam pomysł w tym samym czasie. Ale byłeś trochę szybszy. :) – shang
Tak. 'mzero' i' mplus' w instancji 'MonadPlus' dla' Maybe' są dokładnie takie same jak 'empty' i' <|> 'w instancji' Alternative' dla 'Maybe'. 'MaybeT'' 'mzero' i' mplus' to 'return Nothing' oraz zdefiniowana przeze mnie funkcja" <||> ", z wyjątkiem przypadku, w którym podano moją oryginalną odpowiedź i odpowiedź jozefga. Brakuje nam kompletnego traktatu na ten temat, wyjaśniając, jak przejść od widzenia '(Monad m) => m. f' do napisania transformatora monady dla f, dzięki czemu można zastąpić 'm. f' z nowym typem danych, dzięki czemu możesz zacząć pisać instancje dla niego. – Cirdec
@Cirdec Zaktualizowałem odpowiedź.W ogólnym przypadku może nie być możliwe zbudowanie takiego transformatora, ale właściwie go nie potrzebujemy. Wystarczy mieć monoid i spasować. –