The answer depends on how you want your restriction to be executed: at run time or at compile time.
, (, makeA), . , , , . makeA, A , , , .
:
module Test (Tmp (Foo, Bar, Baz), Test (), makeA) where
data Tmp
= Foo Int
| Bar Int
| Baz Int
data Test = A Tmp Tmp
makeA :: Tmp -> Tmp -> Tmp
makeA (Baz _) (Baz _) = error "makeA: two baz problem"
makeA tmp1 tmp2 = A tmp1 tmp2
, . , .
, - . , , Foo Bar, , Baz. Tmp, , Tmp , - . "Bazness" Tmp .
Bazness Tmp :
data TmpNotBaz
= Foo Int
| Bar Int
data Tmp
= NotBaz TmpNotBaz
| Baz Int
, TmpNotBaz Baz, Tmp Baz. , Haskell. , NotBaz . , - " A Baz, ". A:
data Test
= A1 TmpNotBaz Tmp
| A2 Tmp TmpNotBaz
, , A1 A2 , A (Baz ...) (Baz ...) , . , , , , A (Foo 1) (Foo 2): A1 (Foo 1) (NotBaz (Foo 2)) A2 (NotBaz (Foo 1)) (Foo 2) .
, , , .
Bazness , Tmp , , , Haskell. , , , "" Haskell. , :
{-# LANGUAGE GADTs, TypeFamilies, DataKinds #-}
data Bazness = IsBaz | NotBaz
data BothBazOrNot = BothBaz | NotBothBaz
type family AreBothBaz (b1 :: Bazness) (b2 :: Bazness) :: BothBazOrNot where
AreBothBaz 'IsBaz 'IsBaz = 'BothBaz
AreBothBaz _ _ = 'NotBothBaz
data Tmp (b :: Bazness) :: * where
Foo :: Int -> Tmp 'NotBaz
Bar :: Int -> Tmp 'NotBaz
Baz :: Int -> Tmp 'IsBaz
data Test where
A :: AreBothBaz b1 b2 ~ 'NotBothBaz => Tmp b1 -> Tmp b2 -> Test
, Foo, Bar Baz , -, IsBaz NotBaz. A b1 b2, NotBothBaz.
, :
A (Foo 1) (Bar 2)A (Foo 1) (Baz 2)A (Baz 1) (Bar 2)
A (Baz 1) (Baz 2), :
Couldn't match type 'BothBaz with 'NotBothBaz
arising from a use of A
In the expression: A (Baz 1) (Baz 2)
, , A BothBaz, A, NotBothBaz, , BothBaz NotBothBaz.