2016-08-30 3 views
6

Я пытаюсь добавить ограничение на HList (от бесформенного):Ограничения на HList: проверить одного вхождение типа

  • должен содержать любое произвольное количество элементов типа TA (от 0 до N);
  • он должен содержать один и только один элемент типа TB.

Мой пример имеет этот тип иерархии:

trait T 
case class TA extends T 
case class TB extends T 

привести примеры:

  • tb :: HNil действительна
  • ta :: tb ::HNil действует
  • ta :: tb :: ta :: HNil действует
  • ta :: HNil недействителен
  • HNil недействителен

Я не могу понять, как выразить это как ограничение.

+0

Другие типы, допустимые в hlist? –

+0

Нет, только те, которые расширяют T (и, вероятно, никогда не будет никаких других типов, кроме TA и TB). –

ответ

7

Вы можете сделать это с помощью специального типа, который свидетельствует о том, что существует только один TB, а все остальные элементы - TA. Если вы планируете создать этот список индуктивно, вы увидите, что вам нужно обрабатывать два случая: либо все, что вы видели до сих пор, это TA (что мы можем наблюдать с помощью ToList[T, TA]), а текущий элемент - TB, или вы уже видели один TB и текущий элемент является TA:

import shapeless._, ops.hlist.{ ToList } 

trait T 
case class TA() extends T 
case class TB() extends T 

trait UniqueTB[L <: HList] extends DepFn1[L] { 
    type Out = TB 
    def apply(l: L): TB 
} 

object UniqueTB { 
    def apply[L <: HList](implicit utb: UniqueTB[L]): UniqueTB[L] = utb 
    def getTB[L <: HList](l: L)(implicit utb: UniqueTB[L]): TB = utb(l) 

    implicit def firstTB[T <: HList](
    implicit tl: ToList[T, TA] 
): UniqueTB[TB :: T] = new UniqueTB[TB :: T] { 
    def apply(l: TB :: T): TB = l.head 
    } 

    implicit def afterTB[T <: HList](
    implicit utb: UniqueTB[T] 
): UniqueTB[TA :: T] = new UniqueTB[TA :: T] { 
    def apply(l: TA :: T): TB = utb(l.tail) 
    } 
} 

и потом:

scala> UniqueTB[TB :: HNil] 
res0: UniqueTB[shapeless.::[TB,shapeless.HNil]] = [email protected] 

scala> UniqueTB[TA :: TB :: HNil] 
res1: UniqueTB[shapeless.::[TA,shapeless.::[TB,shapeless.HNil]]] = [email protected] 

scala> UniqueTB[TA :: TB :: TA :: HNil] 
res2: UniqueTB[shapeless.::[TA,shapeless.::[TB,shapeless.::[TA,shapeless.HNil]]]] = [email protected] 

scala> UniqueTB[TB :: HNil] 
res3: UniqueTB[shapeless.::[TB,shapeless.HNil]] = [email protected] 

scala> UniqueTB[TA :: HNil] 
<console>:25: error: could not find implicit value for parameter utb: UniqueTB[shapeless.::[TA,shapeless.HNil]] 
     UniqueTB[TA :: HNil] 
      ^

scala> UniqueTB[HNil] 
<console>:25: error: could not find implicit value for parameter utb: UniqueTB[shapeless.HNil] 
     UniqueTB[HNil] 
      ^

scala> UniqueTB[TB :: TB :: HNil] 
<console>:25: error: could not find implicit value for parameter utb: UniqueTB[shapeless.::[TB,shapeless.::[TB,shapeless.HNil]]] 
     UniqueTB[TB :: TB :: HNil] 
      ^

Я дал класс тип операции, которая возвращает TB, но если вам не нужно, чтобы вы могли оставить его методом-le песчаники

+0

Я думаю, вы могли бы использовать класс типа IsHCons, уже предоставленный бесформенным, вместо создания нового. Единственная оставшаяся вещь - определить 'afterTB' в терминах существующих экземпляров. Как вы думаете? –

+0

На самом деле неважно, не думайте, что вы можете это сделать. : | –

+0

@DenisRosca Да, я не понимаю, как это будет работать, но я мог бы что-то упустить. –

Смежные вопросы