Computação assíncrona com validação em Scala usando Scalaz
Estando escrevendo uma biblioteca completamente assíncrona para acessar um serviço remoto (usando o Play2.0), estou usandoPromise
eValidation
para criar uma chamada sem bloqueio, que tem um tipo apresentando falha e resultado válido de uma só vez.
Promise
vem da Play2-scala, ondeValidation
vem de scalaz.
Então, aqui está o tipo de exemplos de tais funções
f ::A => Promise[Validation[E, B]]
g ::B => Promise[Validation[E, C]]
Até agora, tudo bem, agora se eu quiser compô-los, posso usar o fato de quePromise
apresentar umflatMap
, então eu posso fazer isso para uma compreensão
for (
x <- f(a);
y <- g(b)
) yield y
Ok, eu peguei um atalho para o meu problema aqui porque eu não reutilizei oValidation
resultados dentro da compreensão. Então, se eu quiser reutilizarx
emg
aqui está como eu poderia fazer
for (
x <- f(a); // x is a Validation
y <- x.fold(
fail => Promise.pure(x),
ok => g(ok)
)
) yield y
É justo, mas esse tipo de clichê vai poluir meu código repetidas vezes. O problema aqui é que eu tenho uma espécie de estrutura monádica de dois níveis comoM[N[_]]
.
Neste estágio, existe alguma estrutura na programação que permita trabalhar com essa estrutura pulando facilmente o nível secongo:
for (
x <- f(a); //x is a B
y <- g(b)
) yield y
Agora, abaixo é como eu consegui algo semelhante.
Eu criei uma espécie de estrutura monádica que envolve os dois níveis em um, vamos dizerValidationPromised
que polvilhou oPromise
digite com dois métodos:
def /~> [EE >: E, B](f: Validation[E, A] => ValidationPromised[EE, B]): ValidationPromised[EE, B] =
promised flatMap { valid =>
f(valid).promised
}
def /~~>[EE >: E, B](f: A => ValidationPromised[EE, B]): ValidationPromised[EE, B] =
promised flatMap { valid =>
valid.fold (
bad => Promise.pure(KO(bad)),
good => f(good).promised
)
}
Isso me permite fazer essas coisas
endPoint.service /~~> //get the service
(svc => //the service
svc.start /~~> (st => //get the starting elt
svc.create(None) /~~> //svc creates a new elt
(newE => //the created one
newEntry.link(st, newE) /~~> //link start and the new
(lnk => Promise.pure(OK((st, lnk, newE)))) //returns a triple => hackish
)
)
)
Como podemos ver/~~>
é bem parecido comflatMap
mas pula um nível. O problema é a verbosidade (é por isso que "para compreensão" existe em Scala e "fazer" em Haskell).
Outro ponto, eu tenho o/~>
que fica como ummap
também, mas funciona no segundo nível (em vez do tipo válido -terceiro nível)
Então, minha segunda pergunta é corolária para a primeira ... Estou estudando uma solução sustentável com essa construção?
desculpe por tanto tempo