在这种情况下如何定义Applicative?

时间:2015-01-04 14:08:09

标签: scala concurrency monads applicative

这是我之前quesion的后续内容。我再次阅读post以了解那里描述的设计。

他们引入了与Haxl类似的Job monad。 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] = { ... }

对于并发数据提取,他们添加了新的PairJobMapJob

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 个答案:

答案 0 :(得分:2)

你很快就拥有了PairJob,你有适合你需要的东西。

使用任何泛型类型G(此处为Job)

如果你有配对:

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

(适用于Job,只是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)}
}

反之亦然,如果你有ap和map,你很容易得到对

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 :(得分:1)

你总是可以用flatMap和pure来定义地图:

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

然后你可以用map和flatMap来定义ap:

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)) }
  }