无形:在KList上映射自然变换

问题描述

是否有一种方法可以在KList(例如带有Option ~> Either[String,*]的{​​{1}})上映射自然变换(例如HList)?用KList似乎很自然。

具体地说,我正在尝试执行以下操作:

UnaryTCConstraint

我了解缺少的部分是执行object myNaturalTransformation extends (Option ~> Either[String,*]) { def apply[T](a: Option[T]): Either[String,T] = a.toRight("oh noe!") } def doStuff[KList <: HList: *->*[Option]#λ](klist: KList) = { klist.map(myNaturalTransformation) } 所需的Mapper,Shapeless无法从.map的案例和myNaturalTransformation的案例中生成一个。是否有可能获得另一种方式?还是有另一种方法可以映射我正在忽略的KList(除了将UnaryTCConstraint传递给Mapper函数之外)?

我能够编写自己的doStuff版本,其中包括一个

UnaryTCConstraint

显式生成给定自然变换的映射器。但是,我很好奇是否可以通过Shapeless的def mapper[G[_],HF <: ~>[TC,G]](hf: HF): Mapper[hf.type,L] 实现。

解决方法

UnaryTCConstraint*->*)不是用于映射的,它是一个约束(HListCoproduct,案例类和密封特征是常见的)。对于映射,有类型类NatTRelMappedComappedMapper等(HListCoproduct分开)。 / p>

尝试约束和类型类

def doStuff[KList <: HList: *->*[Option]#λ,L <: HList](klist: KList)(implicit 
  natTRel: NatTRel[KList,Option,L,Either[String,*]]
): L = natTRel.map(myNaturalTransformation,klist)

或只键入class

def doStuff[KList <: HList,klist)

或通过L模式隐藏类型参数PartiallyApplied

def doStuff[KList <: HList] = new PartiallyAppliedDoStuff[KList]

class PartiallyAppliedDoStuff[KList <: HList] {
  def apply[L <: HList](klist: KList)(implicit 
    natTRel: NatTRel[KList,*]]
  ): L = natTRel.map(myNaturalTransformation,klist)
}

或通过存在性隐藏类型参数L(但返回类型不精确)

def doStuff[KList <: HList](klist: KList)(implicit 
  natTRel: NatTRel[KList,_,*]]
) = natTRel.map(myNaturalTransformation,klist)

或使用扩展方法

implicit class NatTRelOps[KList <: HList](val klist: KList) extends AnyVal {
  def map[F[_],G[_],L <: HList](f: F ~> G)(implicit 
    natTRel: NatTRel[KList,F,G]
  ): L = natTRel.map(f,klist)
} 

def doStuff[KList <: HList,*]]
): L = klist.map(myNaturalTransformation)

测试:

doStuff(Option(1) :: Option("a") :: HNil)           // compiles
//doStuff(Option(1) :: Option("a") :: true :: HNil) // doesn't compile