One value constructor, belonging to two different types

Let's say I have three value constructors:

A { a :: Int }
B { b :: Char }
C { c :: Bool }

I would like to create two types Xand Yfor which the type value Xcan be A, Bor C, something like this:

data X = A {...} | B {...} | C {...}

and the type value Ycan only be Aor B, something like this:

data Y = A {...} | B {...}

so that I can encode something like this:

foo :: X -> Int -- can pattern match
foo (A _) = 1
foo (B _) = 2
foo (C _) = 3
bar :: Y -> Bool -- also can pattern match with the same constructors
bar (A _) = true
bar (B _) = false
baz = A 1 -- baz is inferred to be a type that can fit in both X and Y

I know that I can wrap constructors in definitions Xand Yas follows:

data X = XA A | XB B | XC C
data Y = YA A | YB B

( XA A .. ). A, B C X Y, A .. , .

Haskell, GHC?

Edit

, GADT , ( ), , . , , - :

func1 :: [XY Y_] -- returns a list of items that can only be A or B
func1 = ...
func2 = func1 ++ [C True] -- adding a C item to the list

func2 [XY X_], Haskell ( ).

, , OCaml, ( ) OCaml ( "", "" ).

2

. comonad. , , , .: -)

+3
4

, jetxee, , .

, , GADT . , , .

data X_
data Y_
data XY a where
  A :: Int -> XY a
  B :: Char -> XY a
  C :: Bool -> XY X_
type X = XY X_ -- Contains values built with constructors A, B, and C 
type Y = XY Y_ -- Contains only values built with constructors A and B

, A B, X Y. , C, X.

+7
baz = A 1 -- baz is inferred to be a type that can fit in both X and Y

Haskell , . ghc, .

, , , , - :

data Y = A ... | B ...
data X = XY Y | C ...

, A B, Y (A foo) - A foo, Y.

X (A foo), X, A. , , , , , .

+5

foo bar , A _ A, X Y. (X) . , - , :

data X = XA A | XB B | XC C
data Y = YA A | YB B

. ? , X A, B, C, Y A, B. A, B C . , A B , X, Y.

, (X Y ), . , , .

, , , A, B C:

class HasA t where hasA :: t -> Bool
class HasB t where hasB :: t -> Bool
class HasC t where hasC :: t -> Bool

:

data A = A Int
data B = B Char
data C = C Bool
data X = XA A | XB B | XC C
data Y = YA A | YB B

X, Y:

instance HasA X where
  hasA (XA _) = True
  hasA _ = False
instance HasB X where 
  hasB (XB _) = True
  hasB _ = False
instance HasC X where
  hasC (XC _) = True
  hasC _ = False

instance HasA Y where 
  hasA (YA _) = True
  hasA _ = False
instance HasB Y where 
  hasB (YB _) = True
  hasB _ = False
instance HasC Y where 
  hasC = const False

foo bar, X, Y s.

foo :: (HasA t, HasB t, HasC t) => t -> Int
foo v | hasA v = 1
      | hasB v = 2
      | hasC v = 3
      | otherwise = undefined
bar :: (HasA t, HasB t) => t -> Bool
bar v | hasA v = True
      | hasB v = False
      | otherwise = undefined

xs = [ XA (A 1), XB (B '1'), XC (C True) ]
ys = [ YA (A 1), YB (B '1') ]

, foo , HasA, HasB HasC, bar , HasA HasB ( , HasC bar). False , foo bar undefined.

:

ghci> map foo xs
[1,2,3]
ghci> map foo ys
[1,2]
ghci> map bar xs
[True,False,*** Exception: Prelude.undefined
ghci> map bar ys
[True,False]

, bar X s, undefined, , A B. , , , .

A, B C, -, .

class HasA t where getA :: t -> Maybe A

.

+2

Heatsink, :

{-# LANGUAGE GADTs,EmptyDataDecls #-}
module Test where


data NotThatY
data XY a where
  A :: Int -> XY a
  B :: Char -> XY a
  C :: Bool -> XY NotThatY

type Y a = XY a
type X a = XY NotThatY -- or type X =..., but (X a) looks better alongside (Y a).

func1 :: [Y a]
func1 = [A 5, B 'ΓΆ']
func2 :: [X a]
func2 = func1 ++ [C True]

Y . , - a .

type Y = forall a. XY a - .

+1

Source: https://habr.com/ru/post/1776453/


All Articles