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]) 

UPD : columnAttributes은 특정 하위 유형 중 하나의 값을 포함해야하지만, 별개의 서브 타입의 여러 값을 포함 할 수 있습니다.

그래서,이 의사 코드는 정확해야합니다

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

그러나 이것은 실패 :

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

+0

여기에 요점이 누락되었지만 Column? 시공에 대한 검증? –

+0

그래, 나는 이미 그것에 대해 생각했다. 잘못된 값 (예 : 부정적인 '단계')을 구성하는 데 너무 많은 방법이 있으므로이 세트를 고려하지 않아도되므로 전반적으로 가치가 없습니다. 그러나 질문은 여전히 ​​호기심을 위해서만 유효합니다. – chuwy

+3

나는 당신이 시도하고있는 것이 확실하지 않지만, 당신이 끈임을 언급하고 예제를 제공하기 때문에 : 옵션의 HList는 실제로 ADT의 공정한 표현이 아닙니다. HLIST 제품은 다음과 같습니다. 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 

이제 우리는 불행하게도 우리는 이런 종류의 클래스에게 자신을 쓸 필요는 HList는 그래서 모두 EncodeDistKey을 포함 할 수 없습니다 제약 조건해야합니다.

=:=을 사용하여 첫 번째 요소를 확인하고 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' 만 필요합니다. –

관련 문제