Будучи написанием полностью асинхронной библиотеки для доступа к удаленной службе (с использованием Play2.0), я использую Promise
и Validation
, чтобы создать неблокирующий вызов, который имеет отказ представления типа и действительный результат сразу.Асинхронное вычисление с валидацией в Scala с использованием Scalaz
Promise
происходит от Play2-scala, где Validation
происходит от scalaz.
Так вот тип примеров таких функций
- е ::
A => Promise[Validation[E, B]]
- г ::
B => Promise[Validation[E, C]]
До сих пор, так хорошо, теперь, если я хочу, чтобы составить их , Я могу просто использовать тот факт, что Promise
присутствует flatMap
, поэтому я могу сделать это с пониманием
for (
x <- f(a);
y <- g(b)
) yield y
Хорошо, я воспользовался ярлыком для моей проблемы здесь, потому что я не использовал повторно результаты Validation
в понимании. Так что, если я хочу, чтобы повторно использовать x
в g
, вот как я мог бы сделать
for (
x <- f(a); // x is a Validation
y <- x.fold(
fail => Promise.pure(x),
ok => g(ok)
)
) yield y
Справедливо, но этот вид шаблонного будет идти загрязнять свой код снова и снова. Проблема здесь в том, что у меня есть своего рода двухуровневая монадическая структура вроде M[N[_]]
.
На данном этапе, любая структура е ° программирования, что позволяет работать с такой структурой, легко пропуская secong уровень:
for (
x <- f(a); //x is a B
y <- g(b)
) yield y
Теперь, ниже, как я достиг чего-то подобного.
Я создал такую структуру монадических, которая облегает два уровня в одном, скажем ValidationPromised
, который развалюха в Promise
типа с двумя методами:
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
)
}
Это позволяет мне делать такие вещи
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
)
)
)
Как видим, /~~>
очень похож на flatMap
, но пропускает один уровень. Проблема заключается в многословии (вот почему «понимание» существует в Scala и «do» в Haskell).
Еще один момент, у меня /~>
, который стоит как map
также, но работает на втором уровне (вместо допустимого типа - третьего уровень)
Так что мой второй вопрос является следствием бывшего ... Я подхожу к устойчивому решению этой конструкции?
жаль, что так долго
Я уже давно использовал ScalaZ для своих приложений для Play, и это хороший толчок для меня. Я дам вам знать, как я поеду, и, надеюсь, сможет дать здесь осмысленный ответ. – opyate
Да! Спасибо. На самом деле реальная проблема заключается не в использовании ScalaZ с Play. Это более общий вопрос (о f ° prog), потому что без Play (так что только ScalaZ) я использовал 'IO' вместо' Promise'. Следовательно, у меня будет такая же модель, то есть: «IO [Validation [E, A]]' –