Arnon Rotem-Gal-Oz
Arnon Rotem-Gal-Oz

Reputation: 25909

mapping over zipped HLists

I am trying to use shapeless to choose the "non-empty" value from two HLists:

import shapeless.{ HNil, Poly2}

object choose extends Poly2 {
  implicit def caseInt =
    at[Int,Int]{
      case (_,n) if n > 0 => n
      case (o,_) => o
    }

  implicit def caseString  =
    at[String,String] {
      case (_,n) if n.nonEmpty => n
      case(o,_) => o
    }
}


val g = "a" :: "" :: 0 :: HNil
val h = "" :: "a"  :: 5 :: HNil

g.zip(h).map(choose)

I get an error on missing implicit mapper If I understand correctly I need to provide proof that the result of the zip is mappable but I am not sure how to do that

Upvotes: 5

Views: 187

Answers (1)

Gabriele Petronella
Gabriele Petronella

Reputation: 108101

You are very close, but the definition of choose is slightly wrong: map takes a Poly1 not a Poly2.

You're mapping over an hlist of tuples, so you need a polymorphic function taking a single argument (a tuple). What you are providing is instead a polymorphic function taking two arguments. The difference is subtle, but it's there.

Here's a version that works:

import shapeless.{ HNil, Poly1 }

object choose extends Poly1 {
  implicit def caseInt =
    at[(Int,Int)]{
      case (_,n) if n > 0 => n
      case (o,_) => o
    }

  implicit def caseString  =
    at[(String,String)] {
      case (_,n) if n.nonEmpty => n
      case(o,_) => o
    }
}

val g = "a" :: "" :: 0 :: HNil
val h = "" :: "a"  :: 5 :: HNil

g.zip(h).map(choose) // "a" :: "a" :: 5 :: HNil

As you can see what does the trick is extending Poly1 instead of Poly2 and defining the at cases on tuples.

Upvotes: 5

Related Questions