2010-01-21 5 views
10

J'ai besoin de quelques Int s à utiliser comme germe pour la génération de nombres aléatoires et donc je voulais utiliser l'ancienne astuce de l'utilisation de l'heure système en tant que germe.Comment obtenir l'heure du système dans Haskell en utilisant Data.Time.Clock?

J'ai donc essayé d'utiliser le paquet Data.Time et je réussi à faire ce qui suit:

import Data.Time.Clock 

time = getCurrentTime >>= return . utctDayTime 

Quand je lance fois que je reçois des choses comme:

Prelude Data.Time.Clock> time 
55712.00536s 

Le type de time est IO DiffTime. Je m'attendais à voir un type IO Something car cela dépend de choses externes au programme. J'ai donc deux questions:

a) Est-il possible de déballer l'E/S et obtenir la valeur DiffTime sous-jacente?

b) Comment convertir un DiffTime en entier avec sa valeur en secondes? Il y a une fonction secondsToDiffTime mais je n'ai pas pu trouver son inverse.

Répondre

15

Est-il possible de déballer en quelque sorte le IO et obtenir la valeur sous-jacente Taille, Heure Différente?

Oui. Il ya des dizaines de tutoriels sur monades qui expliquent comment. Ils sont tous basés sur l'idée que vous écrivez une fonction qui prend DiffTime et fait quelque chose (par exemple renvoyer IO()) ou retourne simplement un Answer. Donc, si vous avez f :: DiffTime -> Answer, vous écrivez

time >>= \t -> return (f t) 

que certaines personnes préfèrent écrire

time >>= (return . f) 

et si vous avez continue :: DiffTime -> IO() vous avez

time >>= continue 

Ou vous préférez peut-être do notation:

do { t <- time 
    ; continue t -- or possibly return (f t) 
    } 

Pour en savoir plus, consultez l'un des nombreux tutoriels sur les monades.

+0

Je pense pour la simplicité, surtout pour un débutant , vous pouvez omettre la parenthèse en retour. f et pourquoi la syntaxe de style d'espace blanc? – codebliss

+4

@codebliss: pour un débutant, je voulais rendre les choses très explicites et ne pas obliger le lecteur à comprendre les détails de la préséance ou de la mise en page –

+1

Vous pouvez également faire 'f <$> time' puisque chaque monade est un foncteur. IMO ça a l'air très bien. –

7

a) Bien sûr, il est possible d'obtenir la valeur DiffTime; sinon, cette fonction serait plutôt inutile. Vous aurez besoin de lire les monades. This chapter et the next de Real World Haskell a une bonne introduction.

b) Le docs for DiffTime indique qu'il s'agit d'une instance de la classe Real, c'est-à-dire qu'il peut être traité comme un nombre réel, dans ce cas le nombre de secondes. Convertir en secondes est donc une simple question de l'enchaînement des fonctions de conversion:

diffTimeToSeconds :: DiffTime -> Integer 
diffTimeToSeconds = floor . toRational 
+0

Vous perdez les picosecondes de cette façon, cependant. Je fais habituellement 'tronquer. (à partir de la précisionIntegral *). toRational. utctDayTime', qui vous donne le nombre de picosecondes. (Et pour ensemencer un RNG, l'utilisation de cette valeur vous permet d'avoir plus d'un état initial par seconde, ce qui est important dans de nombreuses applications.) – jrockway

+0

(oh, et précision = 10000000000000) – jrockway

7

Si vous envisagez d'utiliser le module standard System.Random pour la génération de nombres aléatoires, il existe déjà un générateur avec une origine dépendant du temps initialisée pour vous: vous pouvez l'obtenir en appelant le getStdGen :: IO StdGen. (Bien sûr, vous avez toujours besoin de la réponse à la partie (a) de votre question pour utiliser le résultat.

0

Cette fonction n'est pas exactement celle demandée par l'OP. Mais c'est utile:

λ: import Data.Time.Clock 
λ: let getSeconds = getCurrentTime >>= return . fromRational . toRational . utctDayTime 
λ: :i getSeconds 
getSeconds :: IO Double  -- Defined at <interactive>:56:5 
λ: getSeconds 
57577.607162 
λ: getSeconds 
57578.902397 
λ: getSeconds 
57580.387334 
Questions connexes