Knows Not Much
Knows Not Much

Reputation: 31546

Not able to build a shapeless HList recursively

I wrote this code

object HList1Test extends App {
   import shapeless.{HList, HNil}
   import shapeless.syntax._
   import shapeless.ops._
   def myFunc(list: List[Int], result: HList = HNil) : HList = {
      def double (i: Int) : HList = if (i % 2 == 0) 2 * i :: HNil else { (2 * i).toString :: HNil}
      list match {
         case h :: t => {
            myFunc(t, double(h) ::: result)
         }
         case Nil => result
      }
   }
   println(myFunc(List(1, 2, 3)))
}

But I get error

Error:(16, 33) could not find implicit value for parameter prepend: shapeless.ops.hlist.Prepend[shapeless.HList,shapeless.HList]
            myFunc(t, double(h) ::: hlist)
Error:(16, 33) not enough arguments for method :::: (implicit prepend: shapeless.ops.hlist.Prepend[shapeless.HList,shapeless.HList])prepend.Out.
Unspecified value parameter prepend.
            myFunc(t, double(h) ::: hlist)

My end goal was to have a HList with "2" :: 4 :: "6" :: HNil

Upvotes: 2

Views: 324

Answers (1)

Dmytro Mitin
Dmytro Mitin

Reputation: 51658

Saying that 2 * i :: HNil and (2 * i).toString :: HNil have type just HList (rather than Int :: HNil and String :: HNil correspondingly) is too rough.

Since double actually returns values of types Int :: HNil or String :: HNil depending on value of its input argument, double is a Poly. So is myFunc.

  object double extends Poly1 {
    implicit def evenCase[N <: Nat](implicit 
      mod: Mod.Aux[N, _2, _0], 
      toInt: ToInt[N]): Case.Aux[N, Int :: HNil] =
      at(n => 2 * toInt() :: HNil)

    implicit def oddCase[N <: Nat](implicit 
      mod: Mod.Aux[N, _2, _1], 
      toInt: ToInt[N]): Case.Aux[N, String :: HNil] =
      at(n => (2 * toInt()).toString :: HNil)
  }

  object myFunc extends Poly2 {
    implicit def hNilCase[R <: HList]: Case.Aux[HNil, R, R] = at((_, r) => r)

    implicit def hConsCase[H <: Nat, T <: HList, 
                           dblH <: HList, R <: HList, 
                           P <: HList, Out <: HList](implicit
      dbl: double.Case.Aux[H, dblH],
      prepend: Prepend.Aux[dblH, R, P],
      myF: myFunc.Case.Aux[T, P, Out]): Case.Aux[H :: T, R, Out] = 
      at { case (h :: t, r) => myFunc(t, double(h) ::: r) }
  }

  println(myFunc(_1 :: _2 :: _3 :: HNil, HNil)) //"6" :: 4 :: "2" :: HNil

Upvotes: 4

Related Questions