我々はHList
としてColumn
にcolumnAttributes
を表す場合は、我々が最初に必要HList
要素をColumnAttribute
というサブタイプに制限し、区別する必要があります。
これを実現するにはhlist constraintsLUBConstraint
とIsDistinctConstraint
を使用できます。
import shapeless.{Default => _, _}
import LUBConstraint._
import IsDistinctConstraint._
def acceptOnlyDistinctAttributes
[L <: HList : <<:[ColumnAttribute]#λ : IsDistinctConstraint](l: L): L = l
今、私たちは、そう、それは残念ながら、我々は、このタイプのクラスに自分自身を記述する必要がある、Encode
とDistKey
の両方を含めることはできませんHList
を制約する必要があります。
=:=
を使用して最初の要素をチェックし、NotContainsConstraint
をチェックして、テールにもう一方のタイプが含まれていないかどうかを確認できます。私たちは今、属性がColumnAttributes
異なることをコンパイル時の保証を持っていないの両方Encode
とは含まれません
type CompressionEncoding = String
sealed trait ColumnAttribute
case class Default(value: String) extends ColumnAttribute
case class Identity(seed: Int, step: Int) extends ColumnAttribute
case class Encode(encoding: CompressionEncoding) extends ColumnAttribute
case object DistKey extends ColumnAttribute
import OnlyOneOfConstraint._
case class Column[
Attrs <: HList
: <<:[ColumnAttribute]#λ
: IsDistinctConstraint
: OnlyOneOf[Encode, DistKey.type]#λ
](columnAttributes: Attrs)
:
trait OnlyOneOfConstraint[L <: HList, A, B] extends Serializable
object OnlyOneOfConstraint {
def apply[L <: HList, A, B]
(implicit ooo: OnlyOneOfConstraint[L, A, B]): OnlyOneOfConstraint[L, A, B] = ooo
type OnlyOneOf[A, B] = {
type λ[L <: HList] = OnlyOneOfConstraint[L, A, B]
}
implicit def hnilOnlyOneOf[A, B] = new OnlyOneOfConstraint[HNil, A, B] {}
// head is A, so tail cannot contain B
implicit def hlistOnlyOneOfA[H, T <: HList, A, B](implicit
ncB: T NotContainsConstraint B,
eq: A =:= H,
oooT: OnlyOneOfConstraint[T, A, B]
) = new OnlyOneOfConstraint[H :: T, A, B] {}
// head is B, so tail cannot contain A
implicit def hlistOnlyOneOfB[H, T <: HList, A, B](implicit
ncA: T NotContainsConstraint A,
eq: B =:= H,
oooT: OnlyOneOfConstraint[T, A, B]
) = new OnlyOneOfConstraint[H :: T, A, B] {}
// head is not A or B
implicit def hlistOnlyOneOf[H, T <: HList, A, B](implicit
neqA: A =:!= H,
neqB: B =:!= H,
oooT: OnlyOneOfConstraint[T, A, B]
) = new OnlyOneOfConstraint[H :: T, A, B] {}
}
は、今、私たちは(簡体字)
Column
これらの制約を使用して書くことができます
DistKey
:
Column(DistKey :: Default("s") :: HNil)
// Column[shapeless.::[DistKey.type,shapeless.::[Default,shapeless.HNil]]] = Column(DistKey :: Default(s) :: HNil)
Column(Default("s") :: Encode("a") :: HNil)
// Column[shapeless.::[Default,shapeless.::[Encode,shapeless.HNil]]] = Column(Default(s) :: Encode(a) :: HNil)
Column(DistKey :: Default("s") :: Encode("a") :: HNil)
// <console>:93: error: could not find implicit value for evidence parameter of type OnlyOneOfConstraint[shapeless.::[DistKey.type,shapeless.::[Default,shapeless.::[Encode,shapeless.HNil]]],Encode,DistKey.type]
// Column(DistKey :: Default("s") :: Encode("a") :: HNil)
ここでポイントがありませんが、カスタムの適用メソッドを追加することはできますか?建設の検証? –
さて、私はすでにそれについて考えました。これらのセットを考慮しなくても無効な値(負の 'ステップ 'など)を作成するには余りにも多くの方法があるため、全体的にはそれにはあまり効果がありません。しかし、質問は好奇心のためだけに有効です。 – chuwy
私はあなたが何をしようとしているのかは分かりませんが、あなたは形がつかないと言い、例を挙げているので、オプションのHListはADTの正式な表現ではありません。 HListsは製品であり、あなたは副産物が必要です:https://github.com/milessabin/shapeless/wiki/Feature-overview:-shapeless-2.0.0#coproducts-and-discriminated-unions – pedrofurla