4 votes

Transformateurs de monades IO et Future[Option].

J'essaie de trouver comment écrire ce morceau de code dans un style élégant et purement fonctionnel en utilisant scalaz7 IO et les transformateurs de monades, mais je n'arrive pas à m'y retrouver.

Imaginez que j'ai cette simple API :

def findUuid(request: Request): Option[String] = ???
def findProfile(uuid: String): Future[Option[Profile]] = redisClient.get[Profile](uuid)

En utilisant cette API, je peux facilement écrire une fonction impure avec le transformateur OptionT comme ceci :

val profileT = for {
  uuid <- OptionT(Future.successful(findUuid(request)))
  profile <- OptionT(findProfile(uuid))
} yield profile
val profile: Future[Option[Profile]] = profileT.run

Comme vous l'avez remarqué - cette fonction contient findProfile() avec un effet de bord. Je veux isoler cet effet à l'intérieur de la monade IO et l'interpréter à l'extérieur de la fonction pure, mais je ne sais pas comment combiner le tout.

def findProfileIO(uuid: String): IO[Future[Option[Profile]]] = IO(findProfile(uuid))

val profileT = for {
  uuid <- OptionT(Future.successful(findUuid(request)))
  profile <- OptionT(findProfileIO(uuid)) //??? how to put Option inside of the IO[Future[Option]]
} yield profile
val profile = profileT.run //how to run transformer and interpret IO with the unsafePerformIO()??? 

Des conseils sur la manière de procéder ?

3voto

Luka Jacobowitz Points 3990

IO est plutôt destiné aux effets synchrones. Task c'est plutôt ce que vous voulez ! Voir cette question et cette réponse : Quelle est la différence entre Task et IO dans Scalaz ?

Vous pouvez convertir votre Future a Task et ensuite avoir une API comme celle-ci :

def findUuid(request: Request): Option[String] = ??? 
def findProfile(uuid: String): Task[Option[Profile]] = ???

Cela fonctionne parce que Task peut représenter à la fois des opérations synchrones et asynchrones, donc findUuid peut également être enveloppé dans Task au lieu de IO .

Vous pouvez ensuite les envelopper dans OptionT :

val profileT = for {
  uuid <- OptionT(Task.now(findUuid(request)))
  profile <- OptionT(findProfileIO(uuid))
} yield profile

Puis à la fin, quelque part, vous pouvez l'exécuter :

profileT.run.attemptRun

Consultez ce lien pour convertir les Futures en Tâches et vice versa : Scalaz Task <-> Future

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