I want to create something that works like this
implicit class HListOps[AHList<:HList](value:AHList){
def fold[R](folder: /*What here?*/)={
}
}
so that it works like this
("HeY"::42::HNil).fold{string=>int=> string+int.toString} // returns "HeY42"
Well, after checking how this problem looks very similar to actually reversing an HList, I used a very similar approach and got this working:
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]
}
Only small problem is that after calling the method fold I have to invoke it using the word apply
without syntactic sugar because otherwise compiler thinks I'm passing the implicit explicitly.