Johann
Johann

Reputation: 25

Scala: Question about shapeless to tranform HList to List

I am new to shapeless (and still low level in the learning curve of scala...) and i have some hard time with shapeless

import shapeless._
case class FooBar[T](foo: String, bar: T)
val hl = 0 :: FooBar("A", "one") :: FooBar("B", 1) :: "0" :: FooBar("C", "two") :: HNil
val l = hl.filter[FooBar[String]].toList
println(l) //List(FooBar(A,one), FooBar(C,two))

It works fine

Next step, i want to put that in function, something like

def filter[T](hl: HList): List[FooBar[T]] = ???

so i can simplify calling to

filter[String](hl)
filter[Int](hl)

naively i tested

def filter[T](hl: HList): List[FooBar[T]] = {
  hl.filter[FooBar[T]].toList
}

which give

 could not find implicit value for parameter partition: shapeless.ops.hlist.Partition[shapeless.HList,FooBar[T]]

after some tries playing with implicit, i still have not found the correct way to do that

Do you have any idea ?

Thank you !

Upvotes: 0

Views: 312

Answers (1)

Dmytro Mitin
Dmytro Mitin

Reputation: 51658

If you lack some implicits then in your method you should suppose they are provided. Saying that an argument of the method is of type just HList (and not some specific L <: HList) is too rough.

Since probably you would like to specify T and not specify L (expecting that L will be inferred) try a type class + extension method

import shapeless._
import shapeless.ops.hlist.{Partition, ToTraversable}

case class FooBar[T](foo: String, bar: T)
val hl = 0 :: FooBar("A", "one") :: FooBar("B", 1) :: "0" :: FooBar("C", "two") :: HNil

trait FilterFooBar[L <: HList, T] {
  def apply(l: L): List[FooBar[T]]
}

object FilterFooBar {
  implicit def mkFilterFooBar[L <: HList, T, Prefix <: HList, Suffix <: HList](implicit
    partition: Partition.Aux[L, FooBar[T], Prefix, Suffix],
    toTraversable: ToTraversable.Aux[Prefix, List, FooBar[T]]
  ): FilterFooBar[L, T] = _.filter.toList    
}

implicit class FilterFooBarOp[L <: HList](l: L) {
  def filterFooBar[T](implicit filterFooBarInstance: FilterFooBar[L, T]): List[FooBar[T]] = 
    filterFooBarInstance(l)
}

println(hl.filterFooBar[String]) // List(FooBar(A,one), FooBar(C,two))
println(hl.filterFooBar[Int]) // List(FooBar(B,1))

Upvotes: 1

Related Questions