给定一个 HList T0::T1:: ... Tn 和类型 R 是否可以推断出函数类型 T0=>T1 ...=> Tn => R?
Given a HList T0::T1:: ... Tn and type R is it possible to infer a function type T0=>T1 ...=> Tn => R?
我想创建这样的东西
implicit class HListOps[AHList<:HList](value:AHList){
def fold[R](folder: /*What here?*/)={
}
}
所以它像这样工作
("HeY"::42::HNil).fold{string=>int=> string+int.toString} // returns "HeY42"
我不认为在 Shapeless 中直接使用某些类型 classes 是可能的,但是可以对类型 (T0, T1, ...) => R
:[=14= 的函数做类似的事情]
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)
遗憾的是,您仍然必须明确指定函数类型的参数。它可以理论上可以定义扩展class到这个:
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)
}
然而,这将要求您知道结果类型 "in advance",这是非常不符合人体工程学的(并且不会真正适用于上面的定义,但可以使其稍微适用更多代码)。
您可以通过要求函数改为接受元组来解决最后一个问题:
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 }
这样,您就不需要为函数指定参数类型,而是函数本身应该接受一个元组,这也符合人体工程学,因为您将不得不使用部分函数语法来从元组参数中解压参数。
好吧,在检查了这个问题看起来与实际反转 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
这个词来调用它,而不使用语法糖,否则编译器会认为我正在显式传递隐式。
我想创建这样的东西
implicit class HListOps[AHList<:HList](value:AHList){
def fold[R](folder: /*What here?*/)={
}
}
所以它像这样工作
("HeY"::42::HNil).fold{string=>int=> string+int.toString} // returns "HeY42"
我不认为在 Shapeless 中直接使用某些类型 classes 是可能的,但是可以对类型 (T0, T1, ...) => R
:[=14= 的函数做类似的事情]
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)
遗憾的是,您仍然必须明确指定函数类型的参数。它可以理论上可以定义扩展class到这个:
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)
}
然而,这将要求您知道结果类型 "in advance",这是非常不符合人体工程学的(并且不会真正适用于上面的定义,但可以使其稍微适用更多代码)。
您可以通过要求函数改为接受元组来解决最后一个问题:
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 }
这样,您就不需要为函数指定参数类型,而是函数本身应该接受一个元组,这也符合人体工程学,因为您将不得不使用部分函数语法来从元组参数中解压参数。
好吧,在检查了这个问题看起来与实际反转 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
这个词来调用它,而不使用语法糖,否则编译器会认为我正在显式传递隐式。