12
votes

Haskell: MONADIC MAIS?

J'ai des fonctions écrites en C que j'appelle de Haskell. Ces fonctions renvoient io (cint) code>. Parfois, je veux exécuter toutes les fonctions, peu importe ce que l'un d'entre eux reviendra, et c'est facile. Pour des mesures d'exemple, il s'agit de l'idée générale de ce qui se passe actuellement:

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


1 commentaires

Il est également un peu décevant que sortby n'est pas défini en termes de Sortbilym :: monad m => (a -> A -> m commande) -> [a] -> m [a ] .


5 Réponses :


11
votes

EDIT: strong> Maintenant, je vois ce que vous cherchez.

gbacon a posté une belle Quel (code> Fonction code>, qui est presque la "primitive" dont vous avez besoin.

En réalité, étant donné que vous êtes seulement intéressé par les effets secondaires, Quelque séquence _ code> devrait suffire. Voici une définition (encore une fois inspirée par Gbacon, votez-le!): P> xxx pré>

Vous appelez cela comme: p> xxx pré>

Réponse originale: strong> p>

Vous ne pouvez pas simplement "bloquer" les valeurs du io code> monad pour une utilisation avec TakeWile CODE>, mais vous pouvez "soulever" Main-quel code> pour une utilisation dans une monade! p>

Le La fonction de levage prendra une fonction (A -> B) code> à un fonction (ma -> mb) code>, où m code> est une monade. p>

(comme une note latérale, vous pouvez trouver une fonction comme celle-ci en recherchant Pour son type sur howogle , dans ce cas en recherchant: monad m => (a -> b) -> (MA -> MB) code> ) p>

avec LifeM Code> Vous pouvez le faire: P>

mapM f [0..1]
=
sequence (map f [0..1])
=
sequence (f 0 : map f [1..1])
=
sequence (f 0 : f 1 : [])
=
sequence ((print 0 >> return 0) : f 1 : [])
= 
sequence ((print 0 >> return 0) : (print 1 >> return 1) : [])
=
do x  <- (print 0 >> return 0)
   xs <- (sequence ((print 1 >> return 1) : []))
   return (x:xs)
=
do x  <- (print 0 >> return 0)
   xs <- (do y  <- (print 1 >> return 1)
             ys <- sequence ([])
             return (y:ys))
   return (x:xs)
=
do x  <- (print 0 >> return 0)
   xs <- (do y  <- (print 1 >> return 1)
             ys <- return []
             return (y:ys))
   return (x:xs)
=
do x  <- (print 0 >> return 0)
   xs <- (do y <- (print 1 >> return 1)
             return (y:[]))
   return (x:xs)
=
do x  <- (print 0 >> return 0)
   xs <- (print 1 >> return (1:[]))
   return (x:xs)
=
do x <- (print 0 >> return 0)
   print 1
   return (x:1:[])
=
do print 0
   print 1
   return (0:1:[])


1 commentaires

Ce n'était pas le vrai comportement que je voulais, mais +1 pour une bonne explication. Le liftm gagne beaucoup plus de sens maintenant.



14
votes

Je ne pense pas qu'il y ait quelque chose comme un à prendre à prendre code> dans la bibliothèque standard, mais vous pouvez l'écrire vous-même de manière à ce que ce soit autant que nécessaire est exécuté:

*Main> takeWhileM (<4) (map f [1..5])
1
2
3
4
[1,2,3]


3 commentaires

Pour la cohérence avec Control.monad.filterm , je m'attendrais à un type de type TakewhtileM :: (Monad M) => (A -> M Bool) -> [A] -> m [a] ; Cela rendrait l'utilisation quelque chose comme rejoindre. Séquence de levage. Takewhilem (lifting (<4)) . Mais c'est un peu plus laidèque pour quel op veut, alors meh.


@sth, @ephemient: pas dans la bibliothèque standard, mais dans mon package "Générateur" nouvellement publié (en piratage), il y a une fonction de prime plus générale. Votre prise de maintien a besoin de la liste des actions pour ne pas dépendre des actions à l'intérieur de la monade, tandis que le générateur est victime d'une liste dont la monade est M, permettant la même chose et plus.


+1 pour correspondre exactement au comportement que je voulais. J'ai mis à jour la question et je vais attendre et voir si quelqu'un a une solution LIB standard. S'il n'y en a pas, j'accepte votre réponse.



6
votes

Vous pouvez utiliser celui de "Liste" Package. XXX < / Pré>

  • FromList [0..5] crée une liste monadique contenant 0..5 qui n'effectue aucune action monadique
  • fmap f à cette liste entraîne un listt io (io int) qui n'active toujours aucune action monadique, contient simplement des utilisateurs.
  • jointM tourne dans un listt io int . Chaque action contenue serait exécutée lorsque l'élément est consommé et que son résultat sera la valeur de la liste.
  • Main-quelconque est généralisé pour toute liste . Les deux [] et " monad m => listt m " sont des instances de Liste . .
  • Exécuter consomme la liste monadique, exécutant toutes ses actions.
  • Si vous êtes intéressé par les résultats que vous pouvez utiliser "Tolist :: Liste m => MA -> Itemm m [a]" " (" itemm (listt io) "est io ). Donc, dans ce cas, c'est " tolist :: listt io a -> io [a] ". Mieux encore, vous pouvez continuer à utiliser des fonctions supérieures telles que scanl , etc. pour traiter la liste monadique telle qu'elle est exécutée.

0 commentaires

15
votes

Vous pouvez définir séquence comme xxx pré>

le problème avec liftm2 code> que vous avez vu est que vous n'avez pas l'occasion d'arrêter m2 code>, qui pourrait être launchthemissiles code>! p> xxx pré>

en utilisant gardien code> comme dans ce qui suit semble attrayant: p>

*Main> untilM (>= 4) as
1
2
3
4


2 commentaires

+1, Nice définition de Quelques-séquences . J'essayais d'abord de le définir en utilisant Foldm au lieu de Plier "/ code>, mais cela ne fonctionnera évidemment pas, car cela oblige toute la liste.


Quelqu'un a suggéré un meilleur nom: Séquencleontil. J'ai aussi ajouté Spanm comme alternative.



3
votes

Plus récemment, vous pouvez utiliser le monadlist Hackage qui inclut Fonctions pratiques comme Takewhilem, DropwriLem, Deletebym et beaucoup plus.


0 commentaires