2012-06-10 4 views
7

Будучи написанием полностью асинхронной библиотеки для доступа к удаленной службе (с использованием 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 также, но работает на втором уровне (вместо допустимого типа - третьего уровень)

Так что мой второй вопрос является следствием бывшего ... Я подхожу к устойчивому решению этой конструкции?

жаль, что так долго

+0

Я уже давно использовал ScalaZ для своих приложений для Play, и это хороший толчок для меня. Я дам вам знать, как я поеду, и, надеюсь, сможет дать здесь осмысленный ответ. – opyate

+0

Да! Спасибо. На самом деле реальная проблема заключается не в использовании ScalaZ с Play. Это более общий вопрос (о f ° prog), потому что без Play (так что только ScalaZ) я использовал 'IO' вместо' Promise'. Следовательно, у меня будет такая же модель, то есть: «IO [Validation [E, A]]' –

ответ

4

Концепция вы ищете здесь monad transformers. Короче говоря, монадные трансформаторы компенсируют monads not composing, позволяя вам «складывать» их.

Вы не указали версию Scalaz, которую используете, но если вы посмотрите в scalaz-seven branch, вы найдете ValidationT. Это можно использовать для обертывания любого F[Validation[E, A]] в ValidationT[F, E, A], где в вашем случае F = Promise. Если вы измените f и g вернуть ValidationT, то вы можете оставить свой код как

for { 
    x ← f(a) 
    y ← g(b) 
} yield y 

Это даст вам ValidationT[Promise, E, B] в результате.

+0

MMmh посмотри, что я ищу! Хорошо, поэтому я сначала попытаюсь с помощью трансформатора монады по двум причинам, потому что это единственный способ узнать, а во-вторых, потому что я на ветке 6.0.4. И тогда я, вероятно, перейду на 7-й и рефакторинг для ValidatorT ... Во всех случаях я собираюсь вернуться сюда, чтобы рассказать больше. Еще раз спасибо –

+0

Ok. Великий док. Я заглянул в 'ValidationT', его метод« flatMap »действительно то, что мне нужно (и, как предполагалось, это то же самое, что и мой'/~~> '). Но для непосредственного использования «Promise» нужен экземпляр TypeClass из «Монады», которого нет. Поэтому, когда ScalaZ выйдет, я реализую его, чтобы иметь возможность использовать 'ValidationT' напрямую. –

Смежные вопросы