95 votes

Différence entre État, ST, IORef et MVar

Je suis en train de travailler à travers Écrire Vous-même un Régime de 48 Heures (j'en suis à environ 85hrs) et j'ai reçu de la part de l'Ajout de Variables et les Affectations. Il y a un grand saut conceptuel dans ce chapitre, et je voudrais qu'il avait été fait en deux étapes avec une bonne refactoring entre les deux, plutôt que de sauter à droite à la solution finale. De toute façon...

J'ai perdu un certain nombre de catégories différentes qui semblent servir le même but: l'Etat, ST, IORef, et MVar. Les trois premiers sont mentionnés dans le texte, tandis que le dernier semble être le favori de répondre à beaucoup de StackOverflow des questions sur les trois premiers. Ils ont tous l'air de réaliser un état entre deux invocations.

Ce sont chacune de ces et en quoi elles diffèrent l'un de l'autre?


En particulier, ces phrases n'ont aucun sens:

Au lieu de cela, nous utilisons une fonctionnalité appelée état threads, laissant Haskell gérer l'état d'agrégation pour nous. Cela nous permet de traiter les variables mutables, comme dans tout autre langage de programmation, à l'aide de fonctions d'obtenir ou de définir des variables.

et

Le IORef module vous permet d'utiliser avec état des variables au sein de l'IO monade.

Tout cela fait de la ligne, type ENV = IORef [(String, IORef LispVal)] - confus pourquoi la deuxième IORef? Ce qui va se briser si je vais écrire `type ENV = State [(String, LispVal)] à la place?

120voto

Don Stewart Points 94361

L'État de Monade : un modèle d'état mutable

L'État de monade est purement fonctionnelle de l'environnement pour les programmes de l'état, avec une API simple:

  • obtenez de l'
  • mettre

La Documentation dans le mtl paquet.

L'État de monade est couramment utilisé lorsqu'il est nécessaire de l'état dans un seul thread de contrôle. Il ne fait pas les utiliser mutable état dans sa mise en œuvre. Au lieu de cela, le programme est paramétrée par la valeur de l'état (c'est à dire l'état est un paramètre supplémentaire à tous les calculs). L'état n'apparaît que pour être muté dans un seul thread (et ne peut pas être partagé entre les threads).

La ST monade et STRefs

La ST monade est restreint, cousin de l'IO monade.

Il permet arbitraire mutable état, mis en œuvre en tant que réel mutable mémoire sur la machine. L'API est fait en sécurité dans des effets secondaires sans programmes, comme le rang 2 type de paramètre empêche les valeurs qui dépendent de la mutable état d'échapper à une portée locale.

Il permet ainsi la mutabilité contrôlée au contraire pur programmes.

Couramment utilisé pour mutable tableaux et d'autres structures de données qui sont mutés, puis congelés. Il est également très efficace, puisque la mutable l'état est "l'accélération matérielle".

Primaire de l'API:

  • De contrôle.Monade.ST
  • runST -- le début d'une nouvelle mémoire de calcul.
  • Et STRefs: les pointeurs (local) mutable cellules.
  • SAINT-base de tableaux (vector), sont aussi fréquentes.

Il pense que le moins dangereux frère de l'IO monade. Ou IO, où vous pouvez lire et écrire dans la mémoire.

IORef : STRefs IO

Ce sont STRefs (voir ci-dessus) dans le IO monade. Ils n'ont pas les mêmes garanties de sécurité que STRefs sur la localité.

MVars : IORefs avec des serrures

Comme STRefs ou IORefs, mais avec un verrou joint, pour sûr simultanées d'accès à partir de plusieurs threads. IORefs et STRefs ne sont à l'abri dans un multi-thread de réglage lors de l'utilisation d' atomicModifyIORef (un compare-and-swap opération atomique). MVars il s'agit d'un mécanisme général pour les partager en toute sécurité les mutable état.

Généralement, en Haskell, l'utilisation MVars ou TVars (STM-fondé mutable cellules), plus de STRef ou IORef.

36voto

John L Points 20989

Ok, je vais commencer par IORef. IORef fournit une valeur qui est mutable dans les IO monade. C'est juste une référence à certaines données, comme une référence, il y a des fonctions qui vous permettent de modifier les données qu'il désigne. En Haskell, l'ensemble de ces fonctions opèrent en IO. Vous pouvez la considérer comme une base de données, de fichiers, ou d'un autre magasin de données externe, vous pouvez obtenir et définir les données, mais cela exige de passer par IO. La raison IO est nécessaire à tous est parce que Haskell est pur; le compilateur a besoin d'un moyen de savoir lequel des données de points de référence à un moment donné (lire sigfpe "Vous pourriez avoir inventé monades" article sur le blog).

MVars sont fondamentalement la même chose comme un IORef, à l'exception de deux des différences très importantes. MVar est une simultanéité primitif, il est donc conçu pour l'accès à partir de plusieurs threads. La deuxième différence est que l' MVar est une boîte qui peut être vide ou plein. Alors, où un IORef Int a toujours un Int (ou est inférieur), un MVar Int peut avoir un Int ou il peut être vide. Si un thread tente de lire une valeur d'un vide MVar, il permet de bloquer jusqu'à ce que l' MVar renseignées (par un autre thread). En gros, une MVar a est équivalent à une IORef (Maybe a) supplémentaires sémantique qui sont utiles pour la concurrence.

State est une monade qui fournit mutable état, pas nécessairement avec IO. En fait, il est particulièrement utile pour de purs calculs. Si vous avez un algorithme qui utilise l'état, mais pas IO, State monade est souvent une solution élégante.

Il y a aussi une monade transformateur version d'Etat, StateT. Il est souvent utilisé pour contenir le programme de configuration de données, ou "jeu-monde-état" types de l'état dans les applications.

ST est quelque chose de légèrement différent. La principale structure de données en ST est le STRef, qui est comme un IORef , mais avec une autre monade. L' ST monade utilise le type de système de ruse ("l'état threads" les docs mention) pour s'assurer que les données mutable peut pas échapper à la monade, c'est, lorsque vous exécutez une ST de calcul, vous obtenez un pur résultat. La raison ST est intéressant, c'est que c'est une monade primitive comme IO, permettant des calculs à effectuer à faible niveau de manipulations sur bytearrays et des pointeurs. Cela signifie qu' ST peut fournir une interface pure tout en utilisant les opérations de bas niveau sur les données mutable, c'est très rapide. Du point de vue du programme, c'est comme si l' ST calcul s'exécute dans un thread séparé avec du fil de stockage local.

16voto

sclv Points 25335

D'autres ont fait le cœur des choses, mais pour répondre à la question directe:

Tout cela fait que le type de ligne ENV = IORef [(String, IORef LispVal)] source de confusion. Pourquoi la deuxième IORef? Ce va casser si je n' type ENV = State [(String, LispVal)] à la place?

Lisp est un langage fonctionnel avec mutable état et de la portée lexicale. Imaginez que vous avez fermé sur une variable mutable. Vous avez maintenant une référence à cette variable traîner à l'intérieur d'une autre fonction -- dire (en haskell-style pseudo-code) (printIt, setIt) = let x = 5 in (\ () -> print x, \y -> set x y). Vous disposez maintenant de deux fonctions, on imprime x, et on définit sa valeur. Lorsque vous évaluez printIt, vous souhaitez rechercher le nom de x dans l'environnement initial dans lequel printIt a été défini, mais vous voulez la recherche de la valeur que le nom est lié à l'environnement dans lequel printIt est appelé (après setIt peut avoir été appelé un certain nombre de fois).

Il existe des moyens besids les deux IORefs pour ce faire, mais vous avez certainement besoin de plus que le dernier type que vous avez proposé, qui ne permet pas de modifier les valeurs que les noms sont liés à un lexicalement étendue de la mode. Google le "funargs problème" pour tout un tas de intéressant la préhistoire.

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