1

I have type

data Type1 = A1 | B1 Bool | C1 Char | D1 Double

and I need second type

data Type2 = A2 Type1

where A2 is restricted to allow A1 or B1 only

I know I can use smart constructor like

mkA2 A1 = A2 A1
mkA2 b@(B1 _) = A2 b

but I wonder is there a way to force restriction on type system level?

2 Answers 2

4

No, this is not possible in vanilla Haskell. You would be better off writing it as

data Type1 = A1 | B1 Bool
data Type2 = A2 Type1 | C2 Char | D2 Double

This doesn't require any language extensions or type system tricks, and it more clearly shows the dependencies in your types with extension rather than restriction. If you want to be able to convert between them, then you can do

type2ToType1 :: Type2 -> Maybe Type1
type2ToType1 (A2 x) = Just x
type2ToType1 _ = Nothing

type1ToType2 :: Type1 -> Type2
type1ToType2 = A2
Sign up to request clarification or add additional context in comments.

Comments

1

Maybe you were asking the more theoretical question? There are many ways of going about this sort of thing with fancy extensions. For example, a GADT can be used to restrict the type of C1 and D1 to Char -> Type1 () and Double -> Type1 () but leave the other constructors open. Thus, everything will be of type Type1 () but only the first two can be of type e.g. Type1 Bool. Here is a variant that also uses -XDataKinds, just for your amusement:

{-# LANGUAGE GADTs, DataKinds, KindSignatures #-}
{-# OPTIONS_GHC -Wall #-}

data Status = Special | Common -- This type we will 'promote' to a kind.
                               -- Its constructors will be used as
                               -- names of (memberless) types.

data Type (s :: Status) where
  A :: Type s
  B :: Bool -> Type s
  C :: Char -> Type Common  
  D :: Double -> Type Common

type Type1 = Type Common  -- This has the same constructors as your Type1 
                          -- i.e. A, B, C and D
type Type2 = Type Special -- This has as many constructors as your Type2
                          -- but doesn't need a new declaration and wrapper
                          -- They are just A and B

mkGeneral :: Type2 -> Type s
mkGeneral A = A
mkGeneral (B b) = B b -- ghc -Wall sees no patterns are missing

mkCommon :: Type2 -> Type1
mkCommon = mkGeneral

mkSpecial :: Type s -> Maybe Type2
mkSpecial A = Just A
mkSpecial (B b) = Just (B b) -- ghc -Wall sees the need for the next line
mkSpecial _ = Nothing

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.