与无形HLists的通用流构建器

时间:2016-04-26 13:22:34

标签: scala shapeless

我有一个简单的构建器,它接受来自Akka流的SourceSink,并且在编译时验证在这些上执行的方法是否具有匹配源和接收器的类型。

class EventProcessorTask(config: EventProcessorConfig =     
  EventProcessorConfig()) {
  def source[In, MatIn](source: Source[In, MatIn]): SourcedTask[In,   MatIn] = new SourcedTask[In, MatIn](source, config)
}

class SourcedTask[In, MatIn](source: Source[In, MatIn], config: EventProcessorConfig) {
  def withPartitioning[Id](partitioningF: In => Id): SourcedTaskWithPartitioning[In, MatIn, Id] =
    new SourcedTaskWithPartitioning[In, MatIn, Id](source, partitioningF, config)
}

class SourcedTaskWithPartitioning[In, MatIn, Id](source: Source[In, MatIn], partitioningF: In => Id, config: EventProcessorConfig) {
  def withSink[Out, T](sink: Sink[Out, T]): WiredTask[In, MatIn, Out :: HNil, Id, Sink[Out, T] :: HNil] =
    new WiredTask[In, MatIn, Out :: HNil, Id, Sink[Out, T] :: HNil](source, sink :: HNil, partitioningF, config)
}

class WiredTask[In, MatIn, L <: HList, Id, SinksTypes <: HList](
                                                             source: Source[In, MatIn],
                                                             sinks: SinksTypes,
                                                             partitioningF: In => Id,
                                                             config: EventProcessorConfig
                                                           ) {
   def withSink[Out, T](sink: Sink[Out, T]): WiredTask[In, MatIn, Out :: L, Id, Sink[Out, T] :: SinksTypes] =
new WiredTask[In, MatIn, Out :: L, Id, Sink[Out, T] :: SinksTypes](
  source, sink :: sinks, partitioningF, config
)

   def execute[N <: Nat, P <: Product, F, R <: HList, SinksRev <: HList]
   ( executionMethod: In => Future[P])(
     implicit generic: Generic.Aux[P, R],
     rev: Reverse.Aux[L, R],
     sinksRev: Reverse.Aux[SinksTypes, SinksRev],
     executionContext: ExecutionContext,
     l: Length.Aux[SinksRev, N]
   ): Unit = {
    val sinksReversed = sinksRev(sinks)

//    val sinksLength= sinksReversed.length.toInt
}
}

上面的代码编译但是当我尝试为Broadcast构建Sinks时,我甚至无法获得列表的大小(注释掉代码)。下一步是将Sinks中的所有SinksRevP中的相应类型相匹配,这样我就可以发送由executionMethod生成的消息,该消息将元组返回{{1}对应于Sinks类型。

即。

P

new EventProcessorTask() .source(Source.single("str")) .withPartitioning(r => 1) .withSink(Sink.head[Long]) .withSink(Sink.foreach((s: String) => ())) .execute( in => Future.successful((null.asInstanceOf[Long], null.asInstanceOf[String])) ) 应该转到第一个LongSink转到第二个。

非常感谢任何帮助。我可能在这里做了一些非常错误的事情,但是当我开始研究这个概念时,这个概念似乎很好(现在不是那么多)。无论哪种方式,我想了解我在这里缺少的东西。

总结一下,问题是: 1.为什么我不能String表示Int大小? 2.如何将SinksRev中的SinkSinksRev中的相应元素相匹配,以构建基于P的{​​{1}}?

1 个答案:

答案 0 :(得分:1)

我最近自己变成了无形的和akka流,所以我决定尝试这个问题。你的情况看起来很复杂,所以我采用了我理解的东西,简化了一下代码似乎做了类似于你可能想要的东西。我仍然无法计算长度,但由于它是一个建造者,那么+= 1就足够了。

这是使用选项而不是接收器的结果。它需要选项列表并将功能应用于选项的内容。正如我所提到的,我简化了案例。

import shapeless._

object Shapes extends App {

  import ops.function._
  import syntax.std.function._

  case class Thing[Types <: HList, Out] private(sources: List[Option[_]]) {

    def withOption[T](o: Option[T]) = Thing[T :: Types, Out](o :: sources)

    def withOutput[T] = Thing[Types, T](sources)

    def apply[F](f: F)(implicit fp: FnToProduct.Aux[F, Types => Out]) = {
      val a: Types = sources.foldLeft[HList](HNil)((m, v) ⇒ v.get :: m ).asInstanceOf[Types]
      f.toProduct(a)
    }
  }

  object Thing {
    def withOption[T](o: Option[T]) = Thing[T :: HNil, AnyVal](o :: Nil)
  }

  val r = Thing
    .withOption(Some(1))
    .withOption(Some(2))
    .withOption(Some(3))
    .withOutput[Unit]
    .apply {
      (x: Int, y: Int, z: Int) ⇒ println(x + y + z)
    }

  println(r)
}