2015-01-04 3 views
1

Это продолжение моих предыдущих quesion. Я читаю это post еще раз, чтобы понять дизайн, описанный там.Как определить аппликативный в этом случае?

Вводят монаду Job, похожую на Haxl. Job[T] - это операция выборки данных, которая извлекает данные типа T (и может состоять из других операций, то есть это последовательность выборки данных).

sealed trait Job[+T] 
case class PureJob[T](value: T) extends Job[T] 
case class BlockedJob[S,T](f: S => Job[T], job: Job[S]) extends Job[T] 
case class FetchJob[T](url: Url) extends Job[T] 

def pure[T](value: T): Job[T] = PureJob(value) 

def flatMap[S,T](f: S => Job[T], job: Job[S]): Job[T] = 
    job match { 
    case PureJob(value) => f(value) 
    case _ => BlockedJob(f, job) 
    } 

Они также ввести функцию execute к фактически выполнить Job[T] операцию и возвращает будущее.

def execute[T](job: Job[T])(implicit ec: ExecutionContext): Future[T] = { ... } 

Для одновременных данных выборки они добавляют новый PairJob и MapJob:

case class MapJob[S, T](f: S => T, job: Job[S]) extends Job[T] 
case class PairJob[S, T](jobS: Job[S], jobT: Job[T]) extends Job[(S, T)] 

Теперь они могут написать:

val jobA: FetchJob[A] = ... 
val jobB: FetchJob[B] = ... 
val f: A => B = ... 

// jobAB is a MapJob of "f" and PairJob of jobA and jobB 
val jobAB = (jobA |@| jobB) {(a, b) => f(a, b)} 

Мой вопрос заключается в том, как определить Job[T], как Applicative к напишите код, как в приведенном выше примере.

ответ

2

Вскоре у вас есть PairJob, у вас есть то, что вам нужно для аппликативного применения.

С любым универсальным типом G, (здесь, что бы работа)

, если у вас есть спаривание:

def pair[A,B](ga: G[A], gb: G[B]): G[(A,B)] 

(который для работы, просто PairJob(ga, gb))

, а также карта , тогда вы можете легко применить применение

def ap[A, B](ga: ⇒ G[A])(f: ⇒ G[A ⇒ B]): G[B] = { 
    val argAndFunc : G[(A, A => B)] = pair(ga, f) 
    argAndFunc map {case (arg, func) => func(arg)} 
} 

Обратное верно, если вы hav е ар и карта, вы легко получить пару

def pair[A,B](ga: G[A], gb: G[B]): G[(A,B)] = { 
    val pairWithB : G[B => (A,B]) = ga map {a => b: B => (a,b)} 
    ap(gb)(pairWithB) 
} 
1

всегда можно определить карту с точки зрения flatMap и чистый:

def map[A,B](fa: Job[A])(f: A=>B): Job[B] = fa flatMap (f andThen pure) 

, а затем вы можете определить ар с точки зрения карты и flatMap:

def ap[A,B](fa: => Job[A])(f: => Job[A => B]): Job[B] = 
    fa flatMap { a => 
    f map (_(a)) 
    } 

или для понимания сахара:

def ap[A,B](fa: => Job[A])(f: => Job[A => B]): Job[B] = 
    for { 
    a <- fa 
    ff <- f 
    } yield ff(a) 

или вы можете пропустить карту:

def ap[A,B](fa: => Job[A])(f: => Job[A => B]): Job[B] = 
    fa flatMap { a => 
    f flatMap { ff => pure(ff(a)) } 
    }