Haskell type of specific data constructor

constructor, haskell, types

Solution

You can use GADTs for this.

{-# LANGUAGE GADTs #-}

data Option a where
    Help :: Option ()
    Opt1 :: Int -> Double -> String -> Option (Int, Double, String)

handleOption :: Option a -> IO ()
handleOption option = case option of
    Help          -> handleHelp
    opt1 @ Opt1{} -> handleOpt1 opt1

handleHelp :: IO ()
handleHelp = print "help"

handleOpt1 :: Option (Int, Double, String) -> IO ()
handleOpt1 (Opt1 n f s) = print (n, f, s)

With GADTs, you give more type information to the compiler. For `handleOpt1`, since it only accepts `Option (Int, Double, String)`, the compiler knows `Option ()` (i.e. `Help`) will never be passed in.

That said, using GADTs makes quite a few other things harder. For instance, automatic deriving (e.g. `deriving (Eq, Show)`) generally doesn't work with them. You should carefully consider the pros and cons of using them in your case.

Problem

Suppose I have the following Haskell code: ``` data Option = Help | Opt1 Int Double String -- more options would be here in a real case handleOption :: Option -> IO () handleOption option = case option of Help -> handleHelp Opt1 n f s -> handleOpt1 n f s handleHelp :: IO () handleHelp = print "help" handleOpt1 :: Int -> Double -> String -> IO () handleOpt1 n f s = print (n, f, s) ``` In the above code, it seems to me a waste to deconstruct the object ahead of time in the sense that I could keep the data bundled neatly together. Now I have to pass each part of Opt1 individually or create a single separate data type to haul them along. Is it possible to pass in the entire `Opt1` to `handleOpt1` while not allowing a general `Option` instance being passed in, such as making `handleOpt1 Help` a compile error? Example pseudo code below: ``` data Option = Help | Opt1 Int Double String handleOption :: Option -> IO () handleOption option = case option of Help -> handleHelp opt1 @ Opt1{} -> handleOpt1 opt1 handleHelp :: IO () handleHelp = print "help" handleOpt1 :: Option:Opt1 -> IO () handleOpt1 (Opt1 n f s) = print (n, f, s) ```

Original source

Related problems