Disons que l'aide de l'IFF, nous avons défini une fonction
c_write :: String -> ()
qui se trouve sur sa pureté, en ce qu'à chaque fois que son résultat est forcé, il affiche la chaîne de caractères. De sorte que nous ne courez pas dans les problèmes de mise en cache dans Michal réponse, nous pouvons définir ces fonctions pour prendre un extra - ()
argument.
c_write :: String -> () -> ()
c_rand :: () -> CUInt
Sur un niveau de mise en œuvre de ce travailler aussi longtemps que le CST n'est pas trop agressif (ce qui n'est pas dans GHC parce que cela peut conduire à des fuites de mémoire, il s'avère). Maintenant que nous avons des choses définies de cette façon, il y a beaucoup de maladroit des questions d'utilisation, Alexis points, mais nous pouvons les résoudre à l'aide d'une monade:
newtype IO a = IO { runIO :: () -> a }
instance Monad IO where
return = IO . const
m >>= f = IO $ \() -> let x = runIO m () in x `seq` f x
rand :: IO CUInt
rand = IO c_rand
Fondamentalement, nous avons juste des trucs tout d'Alexis est maladroit des questions d'utilisation dans une monade, et aussi longtemps que nous utilisons le monadique de l'interface, tout reste prévisible. En ce sens, IO
n'est qu'une convention—parce que nous pouvons mettre en œuvre dans Haskell il n'y a rien de fondamental sur elle.
C'est à partir du point de vue opérationnel.
D'autre part, Haskell de la sémantique dans le rapport sont spécifiées à l'aide de denotational sémantique seul. Et, à mon avis, le fait que Haskell a un denotational la sémantique est l'un des plus beaux et des qualités utiles de la langue, ce qui me permet un cadre précis, à penser à des abstractions et donc de gérer la complexité avec précision. Et tandis que l'habitude abstrait IO
monade n'a pas accepté denotational sémantique (la complainte de certains d'entre nous), c'est au moins concevable que l'on pouvait créer un denotational modèle, permettant ainsi de conserver certains des avantages de Haskell denotational modèle. Toutefois, la forme de I/O, nous avons juste donné est complètement incompatible avec Haskell denotational sémantique.
Tout simplement, il y a seulement censé être distinguer deux valeurs (modulo fatale messages d'erreur) de type ()
: ()
et ⊥. Si nous traitons les FFI que les fondamentaux de l'I/O et l'utilisation de l' IO
monade seulement "la convention", puis nous avons effectivement ajouter un jillion valeurs de chaque type pour continuer à avoir un denotational sémantique, chaque valeur doit être accolé avec la possibilité d'effectuer des e/S avant son évaluation, et, avec le supplément de la complexité de cette présente, nous avons essentiellement perdre tout notre capacité à tenir compte des deux programmes distincts équivalents, sauf dans la plupart des cas triviaux—qui est, nous perdons notre capacité à refactoriser.
Bien sûr, en raison de l' unsafePerformIO
cela est techniquement déjà le cas, et avancé Haskell programmeurs avez besoin de penser à propos de la sémantique opérationnelle ainsi. Mais la plupart du temps, y compris lorsque l'on travaille avec des I/O, nous pouvons oublier tout cela et de refactoriser avec confiance, précisément parce que nous avons appris que lorsque nous utilisons unsafePerformIO
, nous devons être très prudent afin de s'assurer qu'il joue bien, qu'il continue de nous offre autant de denotational raisonnement que possible. Si une fonction a unsafePerformIO
,- je automatiquement donner 5 ou 10 fois plus d'attention que d'ordinaire les fonctions, parce que j'ai besoin de comprendre la validité des modèles d'utilisation (généralement la signature d'un type me dit tout ce que j'ai besoin de savoir), j'ai besoin de réfléchir sur la mise en cache et les conditions de course, j'ai besoin de réfléchir sur la façon profonde j'ai besoin de la force de ses résultats, etc. C'est affreux[1]. Le même soin serait nécessaire de FFI I/O.
En conclusion: oui, c'est une convention, mais si vous ne le suivez pas puis on ne peut pas avoir de belles choses.
[1] et Bien en fait je pense que c'est assez amusant, mais c'est sûrement pas pratique pour penser à toutes ces complexités tout le temps.