How to extract an element from an HList with a specific (parameterized) type

I am chaining transformations and I would like to accumulate the result of each transformation so that it can be used in any subsequent step, and also so that all the results are available at the end (mainly for debugging purposes). There are several steps and from time to time I need to add a new step or change the input for a step.

HList

seems to offer a convenient way to collect results in a flexible yet type-safe way. But I would prefer not to complicate the actual steps so that they deal with HList and the related business.

Here's a simplified version of the combinator that I would like to write that doesn't work. The idea is that if there is an HList containing A and an index A, and the function from A β†’ B, it mapNth

will extract A, run the function and not push the result to the list. As a result, the expanded list captures the type of the new result, so some of these N-mapping steps can be drawn up to create a list containing the result from each step:

def mapNth[L <: HList, A, B]
    (l: L, index: Nat, f: A => B)
    (implicit at: shapeless.ops.hlist.At[L, index.N]):
    B :: L =
  f(l(index)) :: l

      

By the way, I also need map2Nth

with two indices and f: (A, B) => C

, but I believe the problems are the same.

However, it mapNth

doesn't compile, saying it l(index)

has a type at.Out

, but the argument f

must be A

. Of course, this is correct, so I suppose I need to provide evidence that at.Out

in fact A

(or, at.Out <: A

).

Is there a way to express this limitation? I believe it should take the form of an implicit one, because of course the constraint can only be checked when mapNth

applied to a specific list and function.

+3


source to share


1 answer


You know exactly what at.Out

A

, and you can provide this proof by specifying the value of the type member in the type at

:

def mapNth[L <: HList, A, B]
    (l: L, index: Nat, f: A => B)
    (implicit at: shapeless.ops.hlist.At[L, index.N] { type Out = A }):
    B :: L =
  f(l(index)) :: l

      

Companions for type classes at

in Shapeless also define a type Aux

, which includes the inference type as the final type parameter.



def mapNth[L <: HList, A, B]
    (l: L, index: Nat, f: A => B)
    (implicit at: shapeless.ops.hlist.At.Aux[L, index.N, A]):
    B :: L =
  f(l(index)) :: l

      

It's almost equivalent, but more idiomatic (and looks a little better).

+3


source







All Articles