Krever Krever - 2 months ago 17
Scala Question

Omit intermediate types in function signature

I would like to perfom two maps over shapeless HList, I have folllowing code that works:

object doubleToInt extends Poly1 {
implicit def caseDouble = at[Double](_.toInt)

object intToDouble extends Poly1 {
implicit def caseInt = at[Int](_.toDouble)

def convert[InputType<:HList, ResultType<:HList, IntermediateType<:HList](input: InputType)(
implicit mapper1: Mapper.Aux[doubleToInt.type , InputType, IntermediateType],
mapper2: Mapper.Aux[intToDouble.type, IntermediateType, ResultType]
): ResultType = {

convert(2.5 :: HNil)

as we can see the type of
contains a type parameter
that is completely irrelevant to the caller of this function. Is it posible to hide it somehow? It's a problem because I would like to call like this:

convert[SomeType, SomeType2, _](2.5 :: HNil)

but it doesn't compile because of unbound type parameter.


The normal solution when you want to infer only some type parameters of a method call is to split it into 2: the first fixes parameters you are interested in and returns a helper with apply method which is called to infer the rest. Applying this here, you'd get

def convert[ResultType <: HList] = new ConvertTo[ResultType]

class ConvertTo[ResultType <: HList] {
  def apply[InputType <: HList, IntermediateType <: HList](input: InputType)(implicit mapper1: Mapper.Aux[doubleToInt.type, InputType, IntermediateType],
  mapper2: Mapper.Aux[intToDouble.type, IntermediateType, ResultType]
) =

Usage: convertTo[SomeType].apply(2.5 :: HNil). InputType is inferred from input and then the compiler finds the implicit mapper1 and infers IntermediateType.

Or at least, ideally it would: due to the way Scala type inference works, it can't infer IntermediateType from mapper1 and then use it in mapper2, so I am not sure it'll find mapper2 correctly. In future Scala versions this should be fixed by def apply(implicit mapper1: ...)(implicit mapper2: ...), but the pull request enabling this wasn't accepted in time for 2.12.0. If this turns out to be a problem, you'll have to split ConvertTo.apply in 2 again.