Skip to content

Instantly share code, notes, and snippets.

@psttf
Last active December 28, 2015 18:29
Show Gist options
  • Save psttf/7543015 to your computer and use it in GitHub Desktop.
Save psttf/7543015 to your computer and use it in GitHub Desktop.
Find values of the same types in HList
import shapeless._
import poly._
import shapeless.ops.hlist.FlatMapper
object am {
/**
* A type class that helps us partially apply a polymorphic binary function
* to some value and map the resulting function (which of course isn't
* literally a Poly1) over an HList.
*
* See this Stack Overflow question for motivation and some additional
* discussion: http://stackoverflow.com/q/14447487/334519
*
* @author Travis Brown
*/
trait ApplyMapper[HF, A, X <: HList, Out <: HList] {
def apply(a: A, x: X): Out
}
object ApplyMapper {
implicit def hnil[HF, A] = new ApplyMapper[HF, A, HNil, HNil] {
def apply(a: A, x: HNil) = HNil
}
implicit def hlist[HF, A, XH, XT <: HList, OutH, OutT <: HList](implicit
applied: Case2.Aux[HF, A, XH, OutH],
mapper: ApplyMapper[HF, A, XT, OutT]
) = new ApplyMapper[HF, A, XH :: XT, OutH :: OutT] {
def apply(a: A, x: XH :: XT) = applied(a, x.head) :: mapper(a, x.tail)
}
}
}
import am._
trait skip extends Poly2 {
implicit def default[T,U] = at[T,U]((_,_) => HNil)
}
object f extends skip {
implicit def matches[T] = at[T,T]((_,x) => x :: HNil)
}
object mapF extends Poly1 {
implicit def default[T, X <: HList, Out <: HList](implicit
am: ApplyMapper[f.type, T, X, Out],
fm: FlatMapper[poly.identity.type,Out]
) = at[(T, X)] { case (a, x) => am(a, x) flatMap poly.identity }
}
f(false,false)
f(1,"2")
val l = 1 :: true :: "a" :: 2 :: HNil
mapF((2,l))
l.zip(l mapConst l).map(mapF)
@travisbrown
Copy link

Note that in this case you don't need the ApplyMapper machinery:

object mapFilter extends Poly1 {
  implicit def default[A, L <: HList](implicit f: ops.hlist.Filter[L, A]) =
    at[(A, L)] { case (_, l) => l.filter[A] }
}

And then:

scala> l.zip(l mapConst l).map(mapFilter).toList foreach println
1 :: 2 :: HNil
true :: HNil
a :: HNil
1 :: 2 :: HNil

@psttf
Copy link
Author

psttf commented Nov 19, 2013

Thank you very much!

Actually, we are going to use this approach in a slightly different case and we'll need to use the ApplyMapper... Or even something like ApplyFlatMapper: in the example above we flatten the list with _ flatMap poly.identity.

@travisbrown
Copy link

Are you sure you can't do the flattening at the end?—i.e. something like l.zip(l mapConst l).flatMap(mapF)?

@travisbrown
Copy link

(...after moving some stuff around in the l.zip(l mapConst l) part, of course.)

@psttf
Copy link
Author

psttf commented Nov 25, 2013

Hmm... Without flatmaps we have nested lists of the following structure

{[(...),(...)],[(...),(...)]}

We need to flatten inner lists represented by square brackets to get the following structure:

{[......],[......]}

If we flatten at the end we get

{(...),(...),(...),(...)}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment