2017-11-27 21 views
2

나는하나의 특정 데이터 생성자가 다른 데이터 생성자를 허용하지 않고 둘 다 동일한 유형을 제공 할 수 있습니까?

[Leaf 1, Rooted (Leaf 2), Branch (Leaf 3) (Branch (Leaf 4) (Leaf 5))] 

수 있습니다 하스켈 타입 T을 좋아하지만

[Leaf 1, Rooted (Leaf 2), Branch (Rooted (Leaf 3)) (Branch (Leaf 4) (Leaf 5))] 

즉 것입니다. 을 제외한 모든 생성자는 Branch의 첫 번째 또는 두 번째 인수에 나타날 수 있습니다 (전체 코드에는 몇 개의 생성자가 더 있음).

나는 우리가 Branch (Rooted …) …을 할 수 있도록

{-# LANGUAGE GADTs #-} 
data T (x::Bool) where 
    Leaf :: Int -> T True 
    Rooted :: T True -> T False 
    Branch :: T True -> T True -> T True 

같은 것들을 시도했지만 또한 다른 유형 ([T True, T False])의 목록이 될 것이기 때문에 우리가 [Rooted …, One …]을 할 수 없음을 의미했습니다.

은 내가

{-# LANGUAGE GADTs, DataKinds, KindSignatures #-} 
data T where 
    Leaf :: Int -> T 
    Rooted :: T -> T 
    Branch :: UnRooted a => a -> a -> T 
class UnRooted a 
instance UnRooted Leaf 
instance UnRooted Branch 

하지만 GHC을 할 수있는 희망, DataKinds으로 보았다 (7.10.3) Data constructor ‘Leaf’ comes from an un-promotable type ‘T’을 제공합니다.

하스 켈에서이를 수행 할 방법이 있습니까? 당신은 부울 값 숨기는 생성자에서 모든 것을 감싸는 경우

+1

같은 (균질) 목록에 넣으려면 루트와 비 루트에 같은 유형을 지정해야합니다. 그러나 유형이 동일한 경우 하위 트리로 다른 유형을 대체 할 수 있습니다. 이것은 명시된 바와 같이 불가능합니다. 아마도 유형의 부울을 제거하기 위해 실존 적 래퍼에 첫 번째 시도를 래핑하는 것이 좋을까요? 또는 합계 유형을 사용합니까? 또는 GADT가 없으면 루트를 자체 유형으로 설정합니다 (여전히 합계 또는 래퍼 사용). – chi

+2

이유를 설명해 주시겠습니까? 즉,'뿌리 째'생성자는 *에 대해 무엇이되어야할까요? – MathematicalOrchid

+0

패턴 일치 자입니다. 상당히 간단한 구문으로 식을 간단한 목록으로 작성할 수 있기를 바랍니다. 'Branch'는 실제로 두 표현식을 결합하는 연산자 세트입니다. 'Rooted'는 "이 패턴이 이전/다음 패턴 바로 옆에 나타나지 않아도됩니다"와 같은 것을 말하는 래퍼 세트입니다. 그러나 이런 종류의 유형을 깨끗하고 단순한 방식으로 정의하는 것은 어려워 보입니다. 그래서 나는 다른 접근법을 찾아야한다고 생각합니다. – unhammer

답변

3

당신은 최초의 솔루션을 사용할 수 있습니다 : 우리는 어쨌든 유형을 포장해야 위하여려고하는 경우에, 그러나

{-# LANGUAGE GADTs, DataKinds, KindSignatures, RankNTypes #-} 
data T (x::Bool) where 
    Leaf :: Int -> T True 
    Rooted :: T True -> T False 
    Branch :: T True -> T True -> T True 

data TWrap = forall (x :: Bool). TWrap (T x) 

[TWrap $ Leaf 1, TWrap $ Rooted (Leaf 2), TWrap $ Branch (Leaf 3) (Branch (Leaf 4) (Leaf 5))] 

을, 그냥 갈 아마 더 낫다

data T = Leaf Int | Branch T T 
data TWrap = Unrooted T | Rooted T 

[Unrooted $ Leaf 1, Rooted $ Leaf 2, Unrooted $ Branch (Leaf 3) (Branch (Leaf 4) (Leaf 5))] 

뭘 요구하는 것은 기본적으로 dependent types이며, 하스켈이없는 (012 : 유형을 분할하는 더 간단한 솔루션).

+0

종속 유형에 대한 제 의견이 정확하지 않은 경우 제발 수정하십시오. Haskell은 종속 유형 (예 : GADT)을 지원하지만, 질문에 제공된 설명을 충족시키기 위해서는 더 많은 지원이 필요하다고 생각합니다. – Hjulle