Почему Haskell не разрешает двум конструкторам данных совместно использовать «Const» и другие определенные атрибуты данных?

#haskell

#haskell

Вопрос:

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

Я реализую вышеупомянутый конструктор данных с небольшим дополнением,

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

Когда я пытаюсь создать другой конструктор данных ниже, который использует ранее определенный конструктор,

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

  

Я получаю эту ошибку:
«Множественные объявления «Const»»

Та же ошибка следует с Not , And , Imply , и Or . Почему Haskell не разрешает это?

Комментарии:

1. Подумайте о том, каким был бы тип Const , если бы это было разрешено.

Ответ №1:

Haskell не разрешает этого, потому что это было бы неоднозначно. Конструктор значений Prop фактически является функцией, что может быть понятнее, если вы спросите GHCi о его типе:

 > :t Const
Const :: Bool -> Prop
  

Если вы попытаетесь добавить еще один Const конструктор в тот же модуль, у вас будут две «функции», вызываемые Const в одном модуле. У вас этого не может быть.

Комментарии:

1. Обратите внимание, что это, вероятно, не совсем непреодолимая проблема, поскольку такой перегруженный конструктор имеет много общего с методом класса. Будет ли какая-либо такая реализация стоить проблем — это другой вопрос.

Ответ №2:

Это несколько ужасно, но в основном позволит вам делать то, что вы хотите:

 {-# 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 #-}
  

Если https://gitlab.haskell.org/ghc/ghc/-/issues/8583 были когда-либо сделаны, то это можно было бы существенно очистить.