scala – 一个模仿解析器级联的无形HList的提取器
题
创建一个无形的“HList”的提取器可能有些可能,如下所示. val a ~ _ ~ b = 4 :: "so" :: 4.5 :: HNil => a == 4 && b == 4.5 > Replace :: by?,这不应该是问题. 动机 经过多次的汗水和泪水,我设法到达以下代码: for( x1 :: _ :: x2 :: HNil <- (expInt ~ "+" ~ expInt).llE ) yield (x1 + x2) expInt在某些monad E中解析一个Int.(expInt?“”?expInt).llE的类型是E [Int :: String :: Int :: HNil]. 我想在左边的图案 – 在某种程度上类似于右边的组合器解析器的构造. 解决方法
这可以完成,并有一些有趣的曲折.
第一个是,通常,为了匹配使用正确的关联构造函数(即::)构建的结构,您将使用相应的右关联提取器,否则您将以相反的顺序分解和绑定提取的元素.不幸的是,正确的关联提取器必须像正确的关联运算符一样在Scala中结束,这将会破坏您的解析器组合器语法,因为提取器名称必须为?:而不是plain?.不过,我暂时推迟这个工作,并以正确的联系方式工作. 第二个扭转是,我们需要不通用的方法来产生不同类型的结果,这取决于我们是否匹配两个以上元素的HList或两个元素(我们不应该匹配一个较少的元素的列表)所有这两个元素). 如果我们匹配一个多于两个元素的列表,我们需要将列表分解成一个由头和HList尾组成的对,即.给定l:H :: T其中T <:HList我们必须产生类型(H,T)的值.另一方面,如果我们匹配两个元素的列表,即.形式为E1 :: E2 :: HNil,我们需要将列表分解成仅由两个元素组成的对,即(E1,E2),而不是一个头和尾,这将是(E1,E2 :: HNil ). 这可以使用完全相同的类型级编程技术来完成,这些编程技术在整个无形中使用.首先我们定义一个类型类,该类将要执行提取器的工作,其中实例对应于上述两种情况中的每一种, import shapeless._ trait UnapplyRight[L <: HList] extends DepFn1[L] trait LPUnapplyRight { type Aux[L <: HList,Out0] = UnapplyRight[L] { type Out = Out0 } implicit def unapplyHCons[H,T <: HList]: Aux[H :: T,Option[(H,T)]] = new UnapplyRight[H :: T] { type Out = Option[(H,T)] def apply(l: H :: T): Out = Option((l.head,l.tail)) } } object UnapplyRight extends LPUnapplyRight { implicit def unapplyPair[H1,H2]: Aux[H1 :: H2 :: HNil,Option[(H1,H2)]] = new UnapplyRight[H1 :: H2 :: HNil] { type Out = Option[(H1,H2)] def apply(l: H1 :: H2 :: HNil): Out = Option((l.head,l.tail.head)) } } 那么我们就这样定义我们的提取器, object ~: { def unapply[L <: HList,Out](l: L) (implicit ua: UnapplyRight.Aux[L,Out]): Out = ua(l) } 然后我们很好去, val l = 23 :: "foo" :: true :: HNil val a ~: b ~: c = l a : Int b : String c : Boolean 到现在为止还挺好.现在回到关联性问题.如果要使用左关联提取器(即??而不是?:)来实现相同的效果,我们需要改变分解的方式.首先让我们使用刚才使用的正确的关联提取器语法.表达方式, val a ~: b ~: c = l 相当于, val ~:(a,~:(b,c)) = l 相比之下,左关联版本, val a ~ b ~ c = l 相当于, val ~(~(a,b),c) = l 为了使这项工作成为HList的提取者,我们的未应用类型类必须从最后剥离元素,而不是从列表开始.我们可以借助无形的Init和Last类来实现, trait UnapplyLeft[L <: HList] extends DepFn1[L] trait LPUnapplyLeft { import ops.hlist.{ Init,Last } type Aux[L <: HList,Out0] = UnapplyLeft[L] { type Out = Out0 } implicit def unapplyHCons[L <: HList,I <: HList,F] (implicit init: Init.Aux[L,I],last: Last.Aux[L,F]): Aux[L,Option[(I,F)]] = new UnapplyLeft[L] { type Out = Option[(I,F)] def apply(l: L): Out = Option((l.init,l.last)) } } object UnapplyLeft extends LPUnapplyLeft { implicit def unapplyPair[H1,H2)]] = new UnapplyLeft[H1 :: H2 :: HNil] { type Out = Option[(H1,l.tail.head)) } } object ~ { def unapply[L <: HList,Out](l: L) (implicit ua: UnapplyLeft.Aux[L,Out]): Out = ua(l) } 现在我们完成了, val a ~ b ~ c = l a : Int b : String c : Boolean (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |