Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I check in shapeless if a type is a member of an HList?

I'm doing a sequence of preprocessing steps on strings and I was thinking of using HLists to improve the safety of my steps. Some processing steps must be run after others, so I was thinking of encoding that in the type system. My first attempt was:

trait Step
trait Raw extends Step
trait A extends Step
trait B extends Step
trait DependsOnA extends Step
trait DependsOnB extends Step

case class ToBeProcessed[S <: Step](value: String)

object ToBeProcessed {
    def raw(input: String): ToBeProcessed[Raw] = ...
    def doA(input: ToBeProcessed[Raw]): ToBeProcessed[A] = ...
    def doB(input: ToBeProcessed[A]): ToBeProcessed[B] = ...
    def doDependsOnA(input: ToBeProcessed[B]): ToBeProcessed[DependsOnA] = ...
    def doDependsOnB(input: ToBeProcessed[DependsOnA]): ToBeProcessed[DependsOnB] = ...
}

This works, because it forces me to call everything in the sequence doA > doB > doDependsOnA > doDependsOnB, which is a possible order in which it works, but:

  1. it forces dependence between steps that do not depend on each other
  2. if I want to implement a new intermediate step doC I must change the types of things that are unrelated to it

So I started reading about type level lists in Haskell and realized I could use that to encode my dependencies. So I started reading on Shapeless HLists and this popped out:

case class ToBeProcessed[S <: HList](value: String)

object ToBeProcessed {
    def raw(input: String): ToBeProcessed[Raw :: HNil] = ...
    def doA[S <: HList](input: ToBeProcessed[S]): ToBeProcessed[A :: S] = ...
    def doB[S <: HList](input: ToBeProcessed[S]): ToBeProcessed[B :: S] = ...

And to encode the dependency I must have a way to check that A is contained in a given HList:

    def doDependsOnA[S <: HList, ???](input: ToBeProcessed[S]): ToBeProcessed[DependsOnA :: S] = ...

}

where in the ??? type I must somehow encode that S contains A. I'm still not sure how do I do that. Is this possible?

like image 767
Rafael S. Calsaverini Avatar asked Oct 17 '22 17:10

Rafael S. Calsaverini


1 Answers

Shapeless already has a typeclass for proving that a HList contains a certain type: Selector. You would use it like this:

import shapeless._, ops.hlist.Selector

def doDependsOnA[S <: HList](input: ToBeProcessed[S])(implicit ev: Selector[S,A]): ToBeProcessed[DependsOnA :: S] = ???
like image 126
Jasper-M Avatar answered Oct 20 '22 22:10

Jasper-M