【问题标题】:Why / How to separate type construction logic into different classes?为什么/如何将类型构造逻辑分成不同的类?
【发布时间】:2015-11-13 22:04:41
【问题描述】:

this question 中,我注意到需要使用两个类构造函数将逻辑分成两个步骤,但尚未完全理解其背后的基本原理。但我在这里,有一个更复杂的问题。

在这种情况下我需要实现以下目标

    case class RawReq(ip: String, header: Map[String, String] = Map())
    case class Result(status: String, body: Option[String] = None)

    type Directive[T] = T ⇒ Result

    class ActionConstructor[T] {
       def apply[ExtractedRepr <: HList, ExtraInputRepr <: HList]
      (extractor: RawReq ⇒ ExtractedRepr, dir: Directive[T])
      (implicit supplement: Supplement.Aux[T, ExtractedRepr, ExtraInputRepr])
     : ExtraInputRepr => RawReq => Result 
      = ???
    }
    // The Supplement is something to be implemented or replaced ( it should
    // generate a ExtraInputRepr type that basically provide the missing 
    // fields that ExtractedRepr doesn't provide for creating a T,  the
    // example below explains it better.

   //  Example usage below
    case class RequestMessage(name: String, ipAllowed: Boolean, userId: String)

    val dir : Directive[RequestMessage] = (rm: RequestMessage) ⇒ 
       if(rm.ipAllowed) 
         Result("200", Some("hello! " + rm.name )) 
       else Result("401")

    // the extractor can get one piece of information from the RawReq   
    val extractor = (r: RawReq) => ('ipAllowed ->> (r.ip.startWith("10.4")> 3)) :: HNil

    val ac = new ActionConstructor[RequestMessage]

    val action = ac(extractor, dir)

    // The other two fields of RequestMessage are provided throw method call 
    val result = action(('name ->> "Mike") :: ('userId ->> "aId") :: HNil)(RawReq(ip = "10.4.2.5"))  

    result == Result("200", Some("hello! Mike"))

我多次尝试实现这一点都失败了。这是最后一个

  class PartialHandlerConstructor[T, Repr <: HList, ExtractedRepr <: HList]
    (extractor: RawReq ⇒ ExtractedRepr)
    (implicit lgen: LabelledGeneric.Aux[T, Repr]) {
    def apply[TempFull <: HList, InputRepr <: HList]
      (dir: Directive[T])
      (implicit removeAll: RemoveAll.Aux[Repr, ExtractedRepr, InputRepr],
      prepend: Prepend.Aux[InputRepr, ExtractedRepr, TempFull],
      align: Align[TempFull, Repr]): InputRepr ⇒ RawReq ⇒ Result =
        (inputRepr: InputRepr) ⇒ (raw: RawReq) ⇒ {
          dir(lgen.from(align(inputRepr ++ extractor(raw))))
        }
  }

  class HandlerConstructor[T]() {
    def apply[ExtractedRepr <: HList, Repr <: HList]
      (extractor: RawReq ⇒ ExtractedRepr)
      (implicit lgen: LabelledGeneric.Aux[T, Repr]) = {
        new PartialHandlerConstructor[T, Repr, ExtractedRepr](extractor)
    }
  }


  val hc = new HandlerConstructor[RequestMessage]
  val handler1 = hc((r: RawReq) ⇒ ('ipAllowed ->> (r.ip.length > 3)) :: HNil)

  val dir: Directive[RequestMessage] = (rm: RequestMessage) ⇒ Result(rm.ipAllowed.toString, rm.name)

  val action = handler1(dir) // <=== compiler fail

  val result = action(('name ->> "big") :: ('userId ->> "aId") :: HNil)(RawReq("anewiP"))

我收到的编译器错误消息位于 p(dir) 行

错误:(85, 26) 找不到参数 removeAll 的隐式值: shapeless.ops.hlist.RemoveAll.Aux[this.Out,shapeless.::[Boolean with shapeless.labelled.KeyTag [符号与 shapeless.tag.Tagged[String("ipAllowed")],Boolean],shapeless.HNil],InputRepr] val action = handler1(dir) ^

我认为我失败的根本原因是我不明白为什么以及如何将这种类型的构造逻辑组织到不同的类中。而且我不太明白为什么编译器可以在某些情况下找到隐式而不在其他情况下。

【问题讨论】:

    标签: scala shapeless


    【解决方案1】:

    想出了一个解决方案。我必须创建自己的 TypeClass RestOf

    package com.iheart.playSwagger
    
    import org.specs2.mutable.Specification
    import shapeless._
    import ops.hlist._
    import syntax.singleton._
    
    object Test {
      case class RawReq(ip: String, header: Map[String, String] = Map())
    
      case class Result(status: String, body: String)
    
      type Directive[T] = T ⇒ Result
    
      case class RequestMessage(name: String, ipAllowed: Boolean, userId: String)
    
      trait RestOf[L <: HList, SL <: HList] {
        type Out <: HList
      }
    
      object RestOf {
    
        type Aux[L <: HList, SL <: HList, Out0 <: HList] = RestOf[L, SL] { 
          type Out = Out0 
        }
    
        implicit def hlistRestOfNil[L <: HList]: Aux[L, HNil, L] = new RestOf[L, HNil] { type Out = L }
    
        implicit def hlistRestOf[L <: HList, E, RemE <: HList, Rem <: HList, SLT <: HList]
          (implicit rt: Remove.Aux[L, E, (E, RemE)], st: Aux[RemE, SLT, Rem]): Aux[L, E :: SLT, Rem] =
          new RestOf[L, E :: SLT] { type Out = Rem }
      }
    
      class PartialHandlerConstructor[T, Repr <: HList, ExtractedRepr <: HList, InputRepr <: HList]
        (extractor: RawReq ⇒ ExtractedRepr)
        (implicit lgen: LabelledGeneric.Aux[T, Repr]) {
        def apply[TempFull <: HList](dir: Directive[T])
          (implicit prepend: Prepend.Aux[InputRepr, ExtractedRepr, TempFull],
          align: Align[TempFull, Repr]): InputRepr ⇒ RawReq ⇒ Result =
            (inputRepr: InputRepr) ⇒ (raw: RawReq) ⇒ {
              dir(lgen.from(align(inputRepr ++ extractor(raw))))
            }
      }
    
      class HandlerConstructor[T]() {
        def apply[Repr <: HList,ExtractedRepr <: HList, InputRepr <: HList]
        (extractor: RawReq ⇒ ExtractedRepr)
        (implicit lgen: LabelledGeneric.Aux[T, Repr],
         restOf: RestOf.Aux[Repr, ExtractedRepr, InputRepr]) = {
          new PartialHandlerConstructor[T, Repr, ExtractedRepr, InputRepr](extractor)
        }
      }
    
    }
    
    class HandlerSpec extends Specification {
      import Test._
    
    
      "handler" should {
        "generate action functions" in {
          val hc = new HandlerConstructor[RequestMessage]().apply
          val handler1 = hc((r: RawReq) ⇒ ('ipAllowed ->> (r.ip.length > 3)) :: HNil)
    
          val dir: Directive[RequestMessage] = 
            (rm: RequestMessage) ⇒ Result(rm.ipAllowed.toString, rm.name)
    
          val action = handler1(dir)
    
          val result = action(('name ->> "big") :: ('userId ->> "aId") :: HNil)(RawReq("anewiP"))
    
          result === Result("true", "big")
        }
      }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-09
      • 1970-01-01
      • 2011-11-23
      • 2022-05-03
      • 2018-05-22
      • 1970-01-01
      相关资源
      最近更新 更多