Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 929
Arnon Rotem-Gal-Oz Avatar asked Sep 04 '16 22:09

Arnon Rotem-Gal-Oz


1 Answers

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.

like image 134
Gabriele Petronella Avatar answered Oct 02 '22 19:10

Gabriele Petronella