Powerset of an HList of Options

2019-07-08 10:44发布

问题:

I am playing around with Shapeless and I am trying to compute the (kind-of) powerset of an HList of Options. Basically, I want to interpret the HList as a set, in which case the Option value of an element tells me it belongs to the set or not.

For example, given Some(5) :: Some("a") :: HNil, I want to obtain the following HLists:

Some(5) :: Some("a") :: HNil
Some(5) :: None :: HNil
None :: Some("a") :: HNil
None :: None :: HNil

I tried the following:

object test2 extends Poly2{
  implicit def someA[A,B <: HList] : Case.Aux[Some[A], List[B], List[Option[A] :: B]] = at{(a, hls) =>
    val x: List[Option[A] :: B] = hls.flatMap{ hl =>
      List(
        a :: hl,
        None :: hl
      )
    }
    x
  }
  implicit val none : Case.Aux[None.type, List[HList], List[HList]] = at{(_, hls) =>
    hls.map(hl => None :: hl)
  }
}

h.foldRight(List(HNil))(test2)

Without success. I get a failed implicit resolution at the foldRight:

Error:(36, 25) could not find implicit value for parameter folder: shapeless.ops.hlist.RightFolder[Some[Int] :: None.type :: shapeless.HNil,List[shapeless.HNil.type],A$A8.this.test2.type]
h.foldRight(List(HNil))(test2);}
                       ^

I am starting to think that what I want is not possible/makes no sense in Shapeless, because Some[A] and None are different types, and I am trying to mix them like they were not (e.g. the List[Option[A] :: B] in someA), but I would be very happy to be proven wrong. :)

Update to initial question:

Thanks to @Marth's comment, I realized that my code worked fine, as long as I did not use IntelliJ Scala Worksheet! I used a plain object and it worked.
Also, I neeed to add a case to the Poly for Option[A]. The final code is the following:

object combine1 extends Poly2{
    implicit def optionA[A,B <: HList] : Case.Aux[Option[A], List[B], List[Option[A] :: B]] = at{(a, hls) =>
      val x: List[Option[A] :: B] = hls.flatMap{ hl => a match {
          case Some(_) =>
            List(
              None :: hl,
              a :: hl,
            )
          case None =>
            List(None :: hl)
        }
      }
      x
    }

    implicit def someA[A,B <: HList] : Case.Aux[Some[A], List[B], List[Option[A] :: B]] = at{(a, hls) =>
      val x: List[Option[A] :: B] = hls.flatMap{ hl =>
        List(
          None :: hl,
          a :: hl
        )
      }
      x
    }

    implicit val none : Case.Aux[None.type, List[HList], List[HList]] = at{(_, hls) =>
      hls.map(hl => None :: hl)
    }
  }