简体   繁体   中英

Deriving HList of zeroes from a type of HList of Monoids

I am learning shapeless, and currently I am trying to create a function that does the following: given a type of an HList it returns the HList of None s, with the Option types corresponding to given HList type.

For instance:

create[String :: Int :: HNil] // returns None[String] :: None[Int] :: HNil

So the logic is the following:

def create[A <: HList] {
 type HT = ??? //somehow getting Head type
 type TT = ??? //somehow getting Tail type
 // if HT is HNil  HNil else Option.empty[HT] :: create[TT] 
}

Looks like the HT and TT can be provided by IsHCons

def createHList[L <: HList](implicit ihc: IsHCons[L]): HList = {
    type HT = ihc.H
    type TT = ihc.T
    //
}

But that rises two problems

  1. How to compare types?
  2. Compiler can not find IsHCons[TT] for recursive call. (How to get ISHCons[TT] from IsHCons[L] ? It is not even possible for HNil !)

I think that I can get around the (1), by providing implicits for HNil and non HNil , so the compiler will pick up the right implicit, depending on the type.

Am I moving towards the right direction?

Given that, may be it is worth to ask more general question. Given the HList of Monoids, is it possible to derive zero HList , consisting of zeros of give monoids?

Thanks!

It's fairly easy to define Monoid instance for every HList where each element type has its Monoid instance:

trait Monoid[T] {
  def zero: T
  def plus(t1: T, t2: T): T
}

object Monoid {
  implicit val HNilMonoid: Monoid[HNil] = new Monoid[HNil] {
    def zero = HNil
    def plus(hn1: HNil, hn2: HNil) = HNil
  }
  implicit def HConsMonoid[H, T <: HList](implicit hm: Monoid[H], tm: Monoid[T]): Monoid[H :: T] = 
    new Monoid[H :: T] {
      def zero = hm.zero :: tm.zero
      def plus(ht1: H :: T, ht2: H :: T) = 
        hm.plus(ht1.head, ht2.head) :: tm.plus(ht1.tail, ht2.tail)
    }
}

(actually, I would expect shapeless to be able to derive the above automatically, but I'm not an expert on shapeless)

Now, assuming that we have Monoid[Int] and Monoid[String] defined elsewhere, you can just:

implicitly[Monoid[Int :: String :: HNil]].zero

which is exactly what you want, ie a HList of zeros.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM