Obliczenia asynchroniczne z walidacją w Scali przy użyciu Scalaz
Pisząc całkowicie asynchroniczną bibliotekę, aby uzyskać dostęp do usługi zdalnej (używając Play2.0), używamPromise
iValidation
aby utworzyć połączenie niezablokowane, które ma typ prezentujący niepowodzenie i poprawny wynik na raz.
Promise
pochodzi z Play2-scala, gdzieValidation
pochodzi ze skalazu.
Oto rodzaj przykładów takich funkcji
f ::A => Promise[Validation[E, B]]
g ::B => Promise[Validation[E, C]]
Jak dotąd, tak dobrze, teraz, jeśli chcę je skomponować, mogę to w prosty sposób wykorzystaćPromise
przedstawić aflatMap
, więc mogę to zrobić ze zrozumieniem
for (
x <- f(a);
y <- g(b)
) yield y
Ok, zabrałem tutaj skrót do mojego problemu, ponieważ nie użyłem go ponownieValidation
wyniki w ramach for-comprehension. Więc jeśli chcę ponownie użyćx
wg
, oto jak mogę to zrobić
for (
x <- f(a); // x is a Validation
y <- x.fold(
fail => Promise.pure(x),
ok => g(ok)
)
) yield y
Wystarczająco dobrze, ale ten rodzaj kotła będzie w dalszym ciągu zanieczyszczać mój kod. Problem polega na tym, że mam rodzaj dwupoziomowej struktury monadycznejM[N[_]]
.
Czy na tym etapie istnieje jakakolwiek struktura programowania w ° F, która umożliwia pracę z taką strukturą przez łatwe pomijanie drugiego poziomu:
for (
x <- f(a); //x is a B
y <- g(b)
) yield y
Poniżej, w jaki sposób osiągnąłem coś podobnego.
Stworzyłem rodzaj monadycznej struktury, która owija dwa poziomy w jeden, powiedzmyValidationPromised
który zepsułPromise
wpisz dwoma metodami:
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
)
}
To pozwala mi robić takie rzeczy
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
)
)
)
Jak możemy zobaczyć/~~>
jest bardzo podobny doflatMap
ale pomija jeden poziom. Problemem jest gadatliwość (dlatego „for-comprehension” istnieje w Scali i „zrobić” w Haskell).
Kolejny punkt, mam/~>
to jest jakmap
działa również na drugim poziomie (zamiast typu Valid -trzeci poziom)
Więc moje drugie pytanie jest następstwem tego pierwszego ... Czy przy tej konstrukcji popieram zrównoważone rozwiązanie?
przepraszam, że tak długo