Why does Haskell not allow two data constructors to share "Const" and other defined data attributes?

Viewed 99
data Prop = Const Bool
          | Var Char
          | Not Prop
          | And Prop Prop
          | Imply Prop Prop

I am implementing the above data contructor with a minor addition,

data Prop = Const Bool
          | Var Char
          | Not Prop
          | Or Prop Prop
          | And Prop Prop
          | Imply Prop Prop

When I try to make another data contructor below that uses the previously defined constructor,

data Formula = Const Bool
          | Var Prop
          | Not Formula
          | And Formula Formula
          | Or Formula Formula
          | Imply Formula Formula

I get this error: "Multiple declarations of 'Const'"

The same error follows with Not, And, Imply, and Or. Why does Haskell not allow this?

2 Answers

Haskell doesn't allow this because it would be ambiguous. The value constructor Prop is effectively a function, which may be clearer if you ask GHCi about its type:

> :t Const
Const :: Bool -> Prop

If you attempt to add one more Const constructor in the same module, you'd have two 'functions' called Const in the same module. You can't have that.

This is somewhat horrible, but will basically let you do what you want:

{-# LANGUAGE PatternSynonyms, TypeFamilies, ViewPatterns #-}

data Prop = PropConst Bool
          | PropVar Char
          | PropNot Prop
          | PropOr Prop Prop
          | PropAnd Prop Prop
          | PropImply Prop Prop

data Formula = FormulaConst Bool
          | FormulaVar Prop
          | FormulaNot Formula
          | FormulaAnd Formula Formula
          | FormulaOr Formula Formula
          | FormulaImply Formula Formula

class PropOrFormula t where
    type Var t
    constructConst :: Bool -> t
    deconstructConst :: t -> Maybe Bool
    constructVar :: Var t -> t
    deconstructVar :: t -> Maybe (Var t)
    constructNot :: t -> t
    deconstructNot :: t -> Maybe t
    constructOr :: t -> t -> t
    deconstructOr :: t -> Maybe (t, t)
    constructAnd :: t -> t -> t
    deconstructAnd :: t -> Maybe (t, t)
    constructImply :: t -> t -> t
    deconstructImply :: t -> Maybe (t, t)

instance PropOrFormula Prop where
    type Var Prop = Char
    constructConst = PropConst
    deconstructConst (PropConst x) = Just x
    deconstructConst _ = Nothing
    constructVar = PropVar
    deconstructVar (PropVar x) = Just x
    deconstructVar _ = Nothing
    constructNot = PropNot
    deconstructNot (PropNot x) = Just x
    deconstructNot _ = Nothing
    constructOr = PropOr
    deconstructOr (PropOr x y) = Just (x, y)
    deconstructOr _ = Nothing
    constructAnd = PropAnd
    deconstructAnd (PropAnd x y) = Just (x, y)
    deconstructAnd _ = Nothing
    constructImply = PropImply
    deconstructImply (PropImply x y) = Just (x, y)
    deconstructImply _ = Nothing

instance PropOrFormula Formula where
    type Var Formula = Prop
    constructConst = FormulaConst
    deconstructConst (FormulaConst x) = Just x
    deconstructConst _ = Nothing
    constructVar = FormulaVar
    deconstructVar (FormulaVar x) = Just x
    deconstructVar _ = Nothing
    constructNot = FormulaNot
    deconstructNot (FormulaNot x) = Just x
    deconstructNot _ = Nothing
    constructOr = FormulaOr
    deconstructOr (FormulaOr x y) = Just (x, y)
    deconstructOr _ = Nothing
    constructAnd = FormulaAnd
    deconstructAnd (FormulaAnd x y) = Just (x, y)
    deconstructAnd _ = Nothing
    constructImply = FormulaImply
    deconstructImply (FormulaImply x y) = Just (x, y)
    deconstructImply _ = Nothing

pattern Const x <- (deconstructConst -> Just x) where
    Const x = constructConst x

pattern Var x <- (deconstructVar -> Just x) where
    Var x = constructVar x

pattern Not x <- (deconstructNot -> Just x) where
    Not x = constructNot x

pattern Or x y <- (deconstructOr -> Just (x, y)) where
    Or x y = constructOr x y

pattern And x y <- (deconstructAnd -> Just (x, y)) where
    And x y = constructAnd x y

pattern Imply x y <- (deconstructImply -> Just (x, y)) where
    Imply x y = constructImply x y

{-# COMPLETE Const, Var, Not, Or, And, Imply :: Prop #-}
{-# COMPLETE Const, Var, Not, Or, And, Imply :: Formula #-}

If https://gitlab.haskell.org/ghc/ghc/-/issues/8583 were ever done, then this could be substantially cleaned up.

Related