我想创建类似这样的东西
implicit class HListOps[AHList<:HList](value:AHList){
def fold[R](folder: /*What here?*/)={
}
}
以便它像这样
("HeY"::42::HNil).fold{string=>int=> string+int.toString} // returns "HeY42"
答案 0 :(得分:1)
我认为在Shapeless中不能直接使用某些类型类,但是对于类型(T0, T1, ...) => R
的函数可以做类似的事情:
implicit class HListOps[L <: HList](value: L) {
def fold[R, F](folder: F)(implicit ftp: FnToProduct.Aux[F, L => R]): R = {
ftp(folder).apply(value)
}
}
(1 :: "a" :: HNil).fold((x: Int, y: String) => y + x)
不幸的是,您仍然必须为函数类型显式指定参数。从理论上来说可以 定义扩展类:
implicit class HListOps2[L <: HList, F, R](value: L)(implicit ftp: FnToProduct.Aux[F, L => R]) {
def fold(folder: F): R = ftp(folder).apply(value)
}
但是,这将需要您“提前”知道结果类型,这是非常不符合人体工程学的(并且不能真正与上面的定义一起使用,但是可以使它与更多的代码一起使用)
您可以通过要求函数接受一个元组来克服最后一个问题:
implicit class HListOps3[L <: HList, T](value: L)(implicit tup: Tupler.Aux[L, T]) {
def fold[R](folder: T => R): R = folder(tup(value))
}
(1 :: "a" :: HNil).fold { case (x, y) => y + x }
这样,您不需要为函数指定参数类型,而是函数本身应该接受一个元组,这也符合人体工程学,因为您必须使用部分函数语法来解压缩参数从元组参数开始。
答案 1 :(得分:0)
好吧,在检查了这个问题看起来与实际反转HList非常相似之后,我使用了一种非常相似的方法并使它起作用:
import java.time.LocalDate
import scala.language.{higherKinds, reflectiveCalls}
import cats.Applicative
import shapeless._
trait HFolder[InL <: HList, Out] {
type Fld
def fold(inL: InL): Function1[Fld, Out]
}
object HFolder {
implicit def nilHFolder[Out]: HFolder[HNil, Out] {type Fld = Out} = new HFolder[HNil, Out] {
type Fld = Out
override def fold(inL: HNil): Function1[Out, Out] = identity
}
implicit def consHFolder[InH, InT <: HList, Out]
(implicit tailHFolder: HFolder[InT, Out]): HFolder[InH :: InT, Out] {type Fld = InH => tailHFolder.Fld} =
new HFolder[InH :: InT, Out] {
override type Fld = InH => tailHFolder.Fld
override def fold(inL: InH :: InT): Function1[InH => tailHFolder.Fld, Out] = {
folder =>
inL match {
case inH :: inT => tailHFolder.fold(inT)(folder(inH))
}
}
}
implicit class HListOps[InL <: HList](inL: InL) {
def fold[Out](implicit hfolder: HFolder[InL, Out]): Function[hfolder.Fld, Out] = {
hfolder.fold(inL)
}
}
//Here compiler can infer correct info (in this case (String=>Int=>LocalDate)=>LocalDate)
val folder= ("Alejo" :: 29 :: HNil).fold[LocalDate]
}
仅有的一个小问题是,在调用fold方法之后,我必须使用单词apply
来调用它而没有语法糖,因为否则编译器会认为我正在显式传递隐式。