Une façon d'éviter une utilisation commune de unsafePerformIO
-
07-09-2020 - |
Question
J'ai souvent trouver ce modèle dans le code Haskell:
options :: MVar OptionRecord
options = unsafePerformIO $ newEmptyMVar
...
doSomething :: Foo -> Bar
doSomething = unsafePerformIO $ do
opt <- readMVar options
doSomething' where ...
Fondamentalement, on a un dossier d'options ou quelque chose de similaire, qui est initialement fixé au lancement du programme.En tant que programmeur est paresseux, il ne veut pas porter le options
enregistrement de tous les coins du programme.Il définit un MVar
pour garder défini par une vilaine utilisation de unsafePerformIO
.Le programmeur assure, que l'état est défini qu'une seule fois et avant toute opération a eu lieu.Maintenant, chaque partie du programme a utiliser unsafePerformIO
encore une fois, juste pour extraire les options.
À mon avis, une telle variable est considérée comme de façon pragmatique pur (ne me tapez pas).Est-il une bibliothèque qui fait abstraction de ce concept à l'écart et s'assure que la variable est définie qu'une fois, c'est à direqu'aucun appel n'est fait avant que l'initialisation et que l'on ne doit pas écrire unsafeFireZeMissilesAndMakeYourCodeUglyAnd
DisgustingBecauseOfThisLongFunctionName
La solution
Si vous utilisez MVar pour la tenue de paramètres ou quelque chose de similaire, pourquoi n'essayez-vous pas de lecteur de monade?
foo :: ReaderT OptionRecord IO ()
foo = do
options <- ask
fireMissiles
main = runReaderT foo (OptionRecord "foo")
(Et Lecteur régulier si vous n'avez pas besoin IO :P)
Autres conseils
Ceux qui serait essentiel du commerce référentielle de transparence pour un peu de temporaire commodité méritent ni la pureté, ni la commodité.
C'est une mauvaise idée.Le code que vous êtes à la recherche de ce est mauvais code.*
Il n'y a pas moyen de les envelopper ce modèle en toute sécurité, car il n'est pas sûr modèle.Ne pas le faire dans votre code.Ne cherchez pas un moyen sûr de le faire.Il n'y a pas un moyen sûr de le faire.Mettre le unsafePerformIO
sur le sol, lentement, et en arrière loin de la console...
*Il existe des raisons légitimes que les gens utilisent de haut niveau MVars, mais ces raisons ont à voir avec les liaisons à l'étranger de code pour la plupart, ou de quelques autres choses, lorsque l'autre est très salissant.Dans ces cas-là, autant que je sache, cependant, le haut niveau MVars sont pas accessible à partir de derrière unsafePerformIO
.
Utiliser les paramètres implicites.Ils sont un peu moins lourd que de faire de chaque fonction Reader
ou ReaderT
dans son type.Vous ne devez changer le type de signatures de vos fonctions, mais je pense qu'un tel changement peut être scripté.(Serait sympa de faire une fonction pour un Haskell IDE.)
Il y a une raison importante pour ne pas utiliser ce modèle.Autant que je sache, dans
options :: MVar OptionRecord
options = unsafePerformIO $ newEmptyMVar
Haskell donne aucune garantie que options
seront évaluées qu'une seule fois.Depuis le résultat de option
est une pure valeur, il peut être memoized et réutilisés, mais il peut aussi être recalculés pour chaque appel (c'est à direinline) et le sens du programme ne doit pas changer (contrairement à votre cas).
Si vous décidez d'utiliser ce modèle, veillez à ajouter {-# NOINLINE options #-}
, sinon il pourrait se inline et votre programme échoue!(Et par ce que nous sommes en train de sortir de la garantie donnée par la langue et le type de système et en s'appuyant uniquement sur la mise en œuvre d'un compilateur.)
Ce sujet a été largement discuté et solutions possibles sont bien résumées sur Haskell Wiki en Haut niveau de l'état mutable.Actuellement, il n'est pas possible en toute sécurité résumé ce modèle sans compilateur supplémentaires de soutien.
J'ai souvent trouver ce modèle dans le code Haskell:
Lire un code différent.
En tant que programmeur est paresseux, il ne veut pas transporter les options d'enregistrement de tous les coins du programme.Il définit un MVar à garder - défini par une vilaine utilisation de unsafePerformIO.Le programmeur assure, que l'état est défini qu'une seule fois et avant toute opération a eu lieu.Maintenant, chaque partie du programme est d'utiliser unsafePerformIO encore une fois, juste pour extraire les options.
Des sons comme littéralement exactement ce que le lecteur monade accomplit, sauf que le lecteur monade t-il de façon sécuritaire.Au lieu de s'adaptant à votre propre paresse, il suffit d'écrire réelle du bon code.