J'ai un peu de puzzle Je me demandais si vous pouviez m'aider à clarifier.Comment prendre des éléments dans une liste enveloppée dans une monade
Définissons une fonction qui retourne une liste:
let f = replicate 3
Ce que nous voulons faire est la carte de cette fonction à une liste infinie, concaténer les résultats, et ne prendre que les choses qui correspondent à un prédicat.
takeWhile (< 3) $ concatMap f [1..]
Très bien! Cela renvoie [1,1,1,2,2,2]
, ce qui est ce que je veux.
Maintenant, je veux faire quelque chose de similaire, mais la fonction f enveloppe maintenant ses résultats dans une Monade. Dans mon usecase, c'est la monade IO, mais cela fonctionne pour discuter de mon problème:
let f' x = Just $ replicate 3 x
Recenser et concat, je peux utiliser:
fmap concat $ mapM f' [1..5]
qui retourne: Just [1,1,1,2,2,2,3,3,3,4,4,4,5,5,5]
Si Je veux utiliser takeWhile
, cela fonctionne encore:
fmap (takeWhile (< 3) . concat) $ mapM f' [1..5]
qui retourne: Juste [1,1,1,2,2,2]. Génial!
Mais, si je fais la liste sur laquelle j'Epinglez une liste infinie cela ne fait pas ce que je pensais:
fmap (takeWhile (< 3) . concat) $ mapM f' [1..]
On dirait que le takeWhile
est jamais le cas. D'une manière ou d'une autre, je n'obtiens pas le calcul paresseux auquel je m'attendais. Je suis un peu perdu.
Des suggestions sur ce que je peux utiliser à la place? – Daniel
Plus généralement, mapM n'est pas (et ne peut pas être) paresseux pour n'importe quelle monade où (>> =) est strict dans son premier argument. Cela inclut Maybe, [], IO, et bien d'autres choses. – Carl
@Daniel: La seule vraie option est d'écrire explicitement le flux de contrôle que vous avez l'intention de faire. Oui, c'est moins pratique. Tel est le prix du sacrifice de la paresse. – Carl