1377 votes

Qu'est ce qu'une monade?

Après avoir brièvement regardé Haskell récemment, je me demandais si quelqu'un pourrait donner un bref, concis, pratique de l' explication de ce qu'est une monade est essentiellement? J'ai trouvé la plupart des explications que j'ai rencontré à être assez inaccessible et manque de détail pratique, si quelqu'un ici pourrait m'aider?

1037voto

JacquesB Points 19878

Première: Le terme monade est un peu vide de sens si vous n'êtes pas un mathématicien. Un autre terme est le calcul du générateur qui est un peu plus descriptif de ce qu'ils sont réellement utiles.

Vous demandez des exemples pratiques:

Exemple 1: compréhension de Liste:

[x*2 | x<-[1..10], odd x]

Cette expression renvoie le double de tous les nombres impairs dans la gamme de 1 à 10. Très utile!

Il s'avère que c'est vraiment juste sucre syntaxique pour certaines opérations au sein de la Liste monade. La même compréhension de liste peut être écrite comme:

do
   x <- [1..10]
   if odd x 
       then [x * 2] 
       else []

Ou encore:

[1..10] >>= (\x -> if odd x then [x*2] else [])

Exemple 2: Entrée/Sortie:

do
   putStrLn "What is your name?"
   name <- getLine
   putStrLn ("Welcome, " ++ name ++ "!")

Les deux exemples utilise des monades, aka le calcul des constructeurs. Le thème commun est que la monade des chaînes d'opérations dans certains spécifiques, de façon utile. Dans la compréhension de liste, les opérations sont enchaînés de telle sorte que si une opération retourne une liste, puis les opérations suivantes sont effectuées sur chaque élément dans la liste. Le IO monade sur l'autre main effectue les opérations de façon séquentielle, mais passe une "variable cachée", qui représente "l'état du monde", ce qui nous permet d'écrire IO code dans un pur manière fonctionnelle.

Il s'avère que le modèle de chaînage des opérations est très utile, et est utilisé pour beaucoup de choses différentes en Haskell.

Un autre exemple est des exceptions: à l'Aide de l' Error monade, les opérations sont enchaînés, telles qu'elles sont effectuées de manière séquentielle, sauf si une erreur est levée, auquel cas le reste de la chaîne est à l'abandon.

À la fois la liste-de la compréhension de la syntaxe et de la notation sont sucre syntaxique pour le chaînage des opérations à l'aide de l' >>= de l'opérateur. Une monade est fondamentalement juste un type qui prend en charge l' >>= de l'opérateur.

Exemple 3: Un analyseur

C'est très simple analyseur qui analyse une chaîne ou un nombre:

parseExpr = parseString <|> parseNumber

parseString = do
        char '"'
        x <- many (noneOf "\"")
        char '"'
        return (StringValue x)

parseNumber = do
    num <- many1 digit
    return (NumberValue (read num))

Les opérations d' char, digit etc. sont assez simples, ils correspondent ou ne correspondent pas. La magie est la monade qui gère le contrôle de flux: Les opérations sont effectuées de manière séquentielle jusqu'à une correspondance échoue, auquel cas la monade revient à la dernière <|> et tente l'option suivante. De nouveau, une sorte de chaînage des opérations avec certains autres, utiles à la sémantique.

Exemple 4: la programmation Asynchrone

Les exemples ci-dessus sont en Haskell, mais il s'avère F# prend également en charge les monades. Cet exemple est volé de Don Syme:

let AsyncHttp(url:string) =
    async {  let req = WebRequest.Create(url)
             let! rsp = req.GetResponseAsync()
             use stream = rsp.GetResponseStream()
             use reader = new System.IO.StreamReader(stream)
             return reader.ReadToEnd() }

Cette méthode extrait d'une page web. Le punch line est l'utilisation de l' GetResponseAsync - il réellement attend la réponse sur un autre fil, tandis que le thread principal renvoie à partir de la fonction. Les trois dernières lignes sont exécutées sur le pondu fil lorsque la réponse n'a été reçue.

Dans la plupart des autres langues, vous devez créer explicitement une fonction distincte pour les lignes qui gèrent la réponse. L' async monade est capable de "diviser" le bloc sur son propre et surseoir à l'exécution de la seconde moitié. ( async {} De la syntaxe indique que le flux de contrôle dans le bloc est défini par l' async monade)

Comment ils fonctionnent

Alors, comment pouvez-monade faire toutes ces fantaisie de contrôle des flux de chose? Ce qui se passe réellement dans un bloc (ou un calcul de l'expression , comme on les appelle en F#), c'est que chaque opération (en gros à chaque ligne) est enveloppé dans une autre fonction anonyme. Ces fonctions sont ensuite combinées à l'aide de l' bind opérateur (orthographié >>= en Haskell). Depuis l' bind opération combine les fonctions, il peut les exécuter comme il l'entend: de manière séquentielle, à plusieurs reprises, dans le sens inverse, ignorer certains, exécuter certaines sur un thread séparé quand il se sent comme il et ainsi de suite.

Comme un exemple, c'est la version étendue de l'OI-code de l'exemple 2:

putStrLn "What is your name?"
>>= (\_ -> getLine)
>>= (\name -> putStrLn ("Welcome, " ++ name ++ "!"))

C'est la plus laide, mais c'est aussi plus évident que ce qui se passe réellement. L' >>= de l'opérateur est l'ingrédient magique: Elle prend une valeur (sur la gauche) et les combine avec une fonction (sur le côté droit), pour produire une nouvelle valeur. Cette nouvelle valeur est alors prise par le prochain >>= de l'opérateur et de nouveau combiné avec une fonction pour produire une nouvelle valeur. >>= peut être considéré comme un mini-évaluateur.

Notez que >>= est surchargé pour les différents types, de sorte que chaque monade a sa propre implémentation d' >>=. (Toutes les opérations de la chaîne doivent être du type de la même monade bien, sinon l' >>= opérateur ne fonctionnent pas.)

La plus simple possible la mise en œuvre de l' >>= seulement prend de la valeur sur la gauche et l'applique à la fonction sur la droite et renvoie le résultat, mais comme dit avant, ce qui rend l'ensemble du motif est utile quand il y a quelque chose de plus qui se passe dans la monade de mise en œuvre de l' >>=.

Il y a plus d'intelligence dans la façon dont les valeurs sont transmises d'une opération à l'autre, mais cela nécessite une explication plus approfondie de la Haskell type de système.

Résumé

En Haskell-conditions une monade est un type paramétré, qui est une instance de la Monade type de classe, qui définit >>= avec quelques autres opérateurs. En d'autres termes, une monade est juste un type pour lequel l' >>= y est défini.

En soi, >>= est juste lourd sorte d'enchaînement de fonctions, mais avec la présence de la notation qui cache la "plomberie", le monadique des opérations s'avère être une très belle et utile, abstraction, utiles à plusieurs endroits dans la langue, et utile pour créer votre propre mini-langues dans la langue.

Pourquoi sont les monades dur?

Pour de nombreux Haskell-apprenants, les monades sont un obstacle ils ont frappé comme un mur de briques. Ce n'est pas que les monades sont eux-mêmes complexes, mais que la mise en œuvre s'appuie sur de nombreuses autres avancées Haskell caractéristiques comme le type paramétré, les classes de type, et ainsi de suite. Le problème est que Haskell IO est basé sur des monades, et IO est probablement l'une des premières choses que vous voulez comprendre lors de l'apprentissage d'une nouvelle langue - après tout, ce n'est pas beaucoup de plaisir à créer des programmes qui ne produisent pas de sortie. Je n'ai pas de solution immédiate pour ce dilemme de la poule et de l'oeuf problème, sauf le traitement des IO comme "la magie qui se passe ici" jusqu'à ce que vous avez assez d'expérience avec d'autres parties de la langue. Désolé.

702voto

MathematicalOrchid Points 15354

Hoooo garçon! Vous avez demandé à un VFAQ ici. :-D

Je doute que quelqu'un pourra jamais faire défiler cette loin, mais je vais lui donner un aller, de toute façon...


OK, en expliquant "qu'est ce qu'une monade" est un peu comme dire "quel est le nombre?" Nous utilisons les numéros de tous les temps. Mais imaginez que vous avez rencontré quelqu'un qui ne sais rien à propos des chiffres. Comment le diable voulez-vous expliquer quels sont les numéros sont? Et comment voulez-vous même de commencer à décrire pourquoi qui pourrait être utile?

Qu'est ce qu'une monade? La réponse courte: C'est une manière spécifique d'enchaînement de l'ensemble des opérations.

En essence, vous êtes en train de rédiger l'exécution des mesures et de les relier ensemble avec la "fonction de liaison". (En Haskell, il est nommé >>=.) Vous pouvez écrire les appels à la liaison de l'opérateur vous-même, ou vous pouvez utiliser la syntaxe de sucre qui en fait le compilateur insérer les appels de fonction pour vous. Mais de toute façon, chaque étape est séparé par un appel à cette fonction de liaison.

Donc, la fonction de liaison est comme un point-virgule; il sépare les étapes d'un processus. La fonction de liaison de l'emploi est de prendre la sortie de l'étape précédente, et de l'injecter dans l'étape suivante.

Ce n'est pas trop dur, non? Mais il n'y a plus d'une sorte de monade. Pourquoi? Comment?

Ainsi, la fonction de liaison peut prendre juste le résultat d'une étape, et le nourrir à l'étape suivante. Mais si c'est "tous", la monade n'est... ce n'est pas vraiment très utile. Et c'est important de comprendre: Chaque utile monade n'est autre chose en plus à être juste un monade. Chaque utile monade a un "pouvoir spécial", ce qui le rend unique.

(Une monade qui n'a rien de spécial est appelé "l'identité monade". Un peu comme la fonction identité, cela sonne comme une chose tout à fait inutile, pourtant, s'avère ne pas être... Mais c'est une autre histoire™.)

Fondamentalement, chaque monade a sa propre implémentation de la fonction de liaison. Et vous pouvez écrire une fonction de liaison telle qu'elle n'hoopy des choses entre l'exécution des mesures. Par exemple:

  • Si chaque étape renvoie à un échec/réussite de l'indicateur, vous pouvez lier exécuter l'étape suivante que si la précédente a réussi. De cette façon, l'échec de l'étape abandonne l'ensemble de la séquence "automatiquement", sans mise en test auprès de vous. (L' Échec De La Monade.)

  • L'extension de cette idée, vous pouvez mettre en œuvre des "exceptions". (L' Erreur Monade ou Exception Monade.) Parce que vous êtes à la définition de vous-même, plutôt que ce soit une langue fonctionnalité, vous pouvez définir la façon dont ils travaillent. (E. g., peut-être que vous voulez ignorer les deux premières exceptions et seulement abandonner lors d'une troisième exception est levée.)

  • Vous pouvez faire de chaque étape de retour de résultats multiples, et ont la fonction de liaison de la boucle au-dessus d'eux, l'alimentation de chacun dans la prochaine étape pour vous. De cette façon, vous n'avez pas à continuer à écrire des boucles de tous sur la place lorsque vous traitez avec plusieurs résultats. La fonction de liaison "automatiquement" fait tout cela pour vous. (La Liste Monade.)

  • Ainsi que le passage d'un "résultat" d'une étape à une autre, vous pouvez avoir la fonction de liaison passer des données supplémentaires . Ces données maintenant ne s'affiche pas dans votre code source, mais vous pouvez toujours y accéder à partir de n'importe où, sans avoir à passer manuellement à chaque fonction. (Le Lecteur Monade.)

  • Vous pouvez faire en sorte que les "données supplémentaires" peut être remplacé. Cela vous permet de simuler destructrice des mises à jour, sans vraiment faire destructrice des mises à jour. (L' État de Monade et son cousin de l' Écrivain Monade.)

  • Parce que vous êtes seulement la simulation de destructeur des mises à jour, vous pouvez trivialement faire des choses qui seraient impossibles avec de vrais destructeurs de mises à jour. Par exemple, vous pouvez annuler la dernière mise à jour, ou de revenir à une ancienne version.

  • Vous pouvez faire une monade où les calculs peuvent être mis en pause, de sorte que vous pouvez mettre en pause votre programme, allez dans et de bricoler avec l'état interne de données, puis de la reprendre.

  • Vous pouvez mettre en œuvre des "continuations" comme une monade. Cela vous permet de briser l'esprit des gens!

Tout cela et plus encore est possible avec les monades. Bien sûr, tout cela est aussi parfaitement possible sans monades trop. C'est juste considérablement plus facile à l'aide de monades.

183voto

Arnar Points 351

En fait, contrairement à une compréhension commune des Monades, ils n'ont rien à voir avec l'état. Les monades sont tout simplement une façon d'emballer les choses et de fournir des méthodes pour effectuer des opérations sur le enveloppés des trucs sans déballage.

Par exemple, vous pouvez créer un type d'envelopper un autre, en Haskell:

data Wrapped a = Wrap a

Pour envelopper les choses, nous définissons

return :: a -> Wrapped a
return x = Wrap x

Pour effectuer des opérations sans déballage, disons que vous avez une fonction f :: a -> b, alors vous pouvez le faire à soulever que la fonction d'agir sur enveloppé valeurs:

fmap :: (a -> b) -> (Wrapped a -> Wrapped b)
fmap f (Wrap x) = Wrap (f x)

C'est à ce sujet il y a à comprendre. Cependant, il s'avère qu'il est plus général de la fonction pour ce faire de levage, ce qui est bind:

bind :: (a -> Wrapped b) -> (Wrapped a -> Wrapped b)
bind f (Wrap x) = f x

bind peut faire un peu plus que d' fmap, mais pas vice-versa. En fait, fmap peut être définie seulement en termes de bind et return. Ainsi, lors de la définition d'une monade.. vous donner son type (ici, il a été Wrapped a) et de dire comment sa return et bind des opérations de travail.

Le truc cool, c'est que cela ne s'avère être un modèle général, il apparaît dans tous les sens, de l'encapsulation de l'état de manière pure, est l'une d'elles.

Pour un bon article sur la façon dont les monades peuvent être utilisés pour introduire des dépendances fonctionnelles et donc de contrôler l'ordre d'évaluation, comme il est utilisé dans Haskell IO monade, découvrez IO à l'Intérieur.

Comme pour la compréhension de monades, ne vous inquiétez pas trop à ce sujet. Lire à leur sujet ce que vous trouvez intéressant et ne vous inquiétez pas si vous ne comprenez pas tout de suite. Puis il suffit de plonger dans un des langages comme Haskell est le chemin à parcourir. Les monades sont une de ces choses où la compréhension passe dans votre cerveau par la pratique, un jour vous venez de réaliser soudain, vous comprenez.

168voto

nlucaroni Points 21502

Mais, Vous pourriez avoir inventé les Monades!

sigfpe dit:

Mais toutes ces introduire des monades comme quelque chose d'ésotérique dans le besoin d'explication. Mais ce que je veux dire, c'est qu'ils ne sont pas ésotérique. En fait, confronté à divers problèmes dans la programmation fonctionnelle, vous auriez été conduit, inexorablement, à certaines solutions, qui sont tous des exemples de monades. En fait, j'espère pour vous de les inventer maintenant, si vous ne l'avez pas déjà. C'est alors qu'un petit pas à remarquer que toutes ces solutions sont en fait la même solution dans le déguisement. Et après cette lecture, vous pourriez être dans une meilleure position pour comprendre les autres documents sur les monades parce que vous le reconnaîtrez tout ce que vous voyez quelque chose que vous avez déjà inventé.

Beaucoup des problèmes que les monades essayer de résoudre sont liés à la question des effets secondaires. Donc nous allons commencer avec eux. (Notez que les monades vous permettre de faire plus que de gérer les effets secondaires, en particulier, de nombreux types d'objet conteneur peuvent être considérés comme des monades. Certains des introductions à des monades du mal à concilier ces deux usages différents de monades et de se concentrer sur l'un ou l'autre).

Dans un impératif langage de programmation comme le C++, les fonctions se comportent rien de tel que les fonctions mathématiques. Par exemple, supposons que nous avons une fonction C++ qui prend une seule virgule flottante argument et renvoie un résultat en virgule flottante. Superficiellement, il semble un peu comme une fonction mathématique de la cartographie réels réels, mais une fonction C++ peuvent faire plus que simplement retourner un nombre qui dépend de ses arguments. Il peut lire et écrire les valeurs des variables globales ainsi que l'écriture de la sortie à l'écran et la réception de l'entrée de l'utilisateur. Dans un langage purement fonctionnel, cependant, une fonction ne peut lire ce qui est fourni dans ses arguments et la seule façon dont il peut avoir un effet sur le monde à travers les valeurs qu'elle renvoie.

87voto

Chris Conway Points 24671

Une monade est un type de données qui comporte deux opérations: >>= (aka bind) et return (aka unit). return prend une valeur arbitraire et crée une instance de la monade. >>= prend une instance de la monade et de cartes d'une fonction sur elle. (Vous pouvez déjà voir qu'une monade est une étrange sorte de type de données, comme dans la plupart des langages de programmation, vous ne pouviez pas écrire une fonction qui prend une valeur arbitraire et crée un type de. Les monades utiliser une sorte de polymorphisme paramétrique.)

Dans la notation Haskell, la monade interface est écrit

class Monad m where
  return :: a -> m a
  (>>=) :: forall a b . m a -> (a -> m b) -> m b

Ces opérations sont censés obéir à certaines "lois", mais ce n'est pas très important: les "lois" juste codifier la façon sensée implémentations des opérations devrait comporter (à la base, c' >>= et return devrait d'accord sur la façon dont les valeurs se transforme en monade instances et qu' >>= est associative).

Les monades ne sont pas seulement à propos de l'état et IO: ils abstraite d'un modèle commun de calcul qui inclut le travail avec l'état, IO, les exceptions, et le non-déterminisme. Probablement le plus simple des monades à comprendre sont les listes et les types d'options:

instance Monad [ ] where
    []     >>= k = []
    (x:xs) >>= k = k x ++ (xs >>= k)
    return x     = [x]

instance Monad Maybe where
    Just x  >>= k = k x
    Nothing >>= k = Nothing
    return x      = Just x

[] et : sont la liste des constructeurs, ++ est l'opérateur de concaténation, et Just et Nothing sont Maybe constructeurs. Deux de ces monades encapsuler courantes et les plus utiles des modèles de calcul sur leurs types de données (remarque qui n'a rien à voir avec des effets secondaires ou IO).

Vous avez vraiment de jouer autour de l'écriture de certains non-triviale du code Haskell à apprécier ce que les monades sont et pourquoi ils sont utiles.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X