2

Getting subclasses of a sealed traitこれは部分的にこの質問と重複していますが、答えは私には不適切な実行時リフレクションを示唆しており、コンパイル時におそらくシェイプレスを使用しているかどうかを知りたいと思います。代数データ型の型レベルセット

ので、このADTを持つ:

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 

どのように私はOption[Default] :: Option[Identity] :: Option[Encode] :: Option[DistKey] :: HNilような何かを得ることができますか?

もっと具体的な質問(おそらく私は間違った解決策を探しています)。 上記のASTとそれに続くクラスでは、ColumnEncodeまたはDistKeyまたは他のColumnAttributeで構成されないことをコンパイル時にどのように確認できますか。

case class Column(columnName: String, dataType: DataType, columnAttributes: Set[ColumnAttribute], columnConstraints: Set[ColumnConstraint]) 

UPDcolumnAttributesは、特定のサブタイプの一つの値だけを含むべきであるが、異なるサブタイプの複数の値を含むことができます。

ので、この擬似コードは正しいはずです:

columnConstraint = Default("foo") :: DistKey :: Identity(1,2) :: HNil

しかし、これは失敗するはずです:

columnConstraint = Default("foo") :: Default("bar") :: HNil

+0

ここでポイントがありませんが、カスタムの適用メソッドを追加することはできますか?建設の検証? –

+0

さて、私はすでにそれについて考えました。これらのセットを考慮しなくても無効な値(負の 'ステップ 'など)を作成するには余りにも多くの方法があるため、全体的にはそれにはあまり効果がありません。しかし、質問は好奇心のためだけに有効です。 – chuwy

+3

私はあなたが何をしようとしているのかは分かりませんが、あなたは形がつかないと言い、例を挙げているので、オプションのHListはADTの正式な表現ではありません。 HListsは製品であり、あなたは副産物が必要です:https://github.com/milessabin/shapeless/wiki/Feature-overview:-shapeless-2.0.0#coproducts-and-discriminated-unions – pedrofurla

答えて

3

我々はHListとしてColumncolumnAttributesを表す場合は、我々が最初に必要HList要素をColumnAttributeというサブタイプに制限し、区別する必要があります。

これを実現するにはhlist constraintsLUBConstraintIsDistinctConstraintを使用できます。

import shapeless.{Default => _, _} 
import LUBConstraint._ 
import IsDistinctConstraint._ 

def acceptOnlyDistinctAttributes 
    [L <: HList : <<:[ColumnAttribute]#λ : IsDistinctConstraint](l: L): L = l 

今、私たちは、そう、それは残念ながら、我々は、このタイプのクラスに自分自身を記述する必要がある、EncodeDistKeyの両方を含めることはできません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) 
+0

)。ありがとう@PeterNeyens。これは私の質問に部分的に答えます。部分的には、私はそれを明確にはっきりさせていないようだ(更新されたトピック)。しかし、それは私の好奇心を満たして、シェイプレスのすごいスクラップのように見えます。 – chuwy

+1

あなたの更新された質問では、 'OnlyOneOf'制約は必要なく、単に' LUB'と 'IsDistinct'が必要なようです。 –

関連する問題