加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

scala – 一个模仿解析器级联的无形HList的提取器

发布时间:2020-12-16 09:17:03 所属栏目:安全 来源:网络整理
导读:题 创建一个无形的“HList”的提取器可能有些可能,如下所示. val a ~ _ ~ b = 4 :: "so" :: 4.5 :: HNil= a == 4 b == 4.5 Replace :: by?,这不应该是问题. 摆脱终止HNIL.是否有任何可能出现的问题? 动机 经过多次的汗水和泪水,我设法到达以下代码: for( x

创建一个无形的“HList”的提取器可能有些可能,如下所示.

val a ~ _ ~ b = 4 :: "so" :: 4.5 :: HNil
=> a == 4 && b == 4.5

> Replace :: by?,这不应该是问题.
>摆脱终止HNIL.是否有任何可能出现的问题?

动机

经过多次的汗水和泪水,我设法到达以下代码:

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

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读