Haskell 是否可能有一个数据类型只有另一个数据类型的一个构造函数?

Haskell 是否可能有一个数据类型只有另一个数据类型的一个构造函数?,haskell,types,constructor,Haskell,Types,Constructor,我有一个非常复杂的数据类型: data SomeDataType = Constructor Blah Blah Blah | OtherConstructor Blah Yadda | YetAnotherConstructor Yadda Yadda Tittle | StillOneMoreConstructor Tittle Tattle Wish Wash data YetAnotherData = YetAnotherConstructor Yadda Yadda Tittle d

我有一个非常复杂的数据类型:

data SomeDataType = Constructor Blah Blah Blah | OtherConstructor Blah Yadda | YetAnotherConstructor Yadda Yadda Tittle | StillOneMoreConstructor Tittle Tattle Wish Wash
data YetAnotherData = YetAnotherConstructor Yadda Yadda Tittle
data SomeDataType   = Constructor Blah Blah Blah
                    | OtherConstructor Blah Yadda
                    | SomeYetAnotherConstructor {-!-}YetAnotherData
                    -- ! will make this EXACTLY isomorphic to the original 
                    -- but is likely unnecessary 
                    | StillOneMoreConstructor Tittle Tattle Wish Wash
data WantedDataType = ConstructorName1 Double
                    | ConstructorName2 {-!-}YetAnotherData
现在我发现自己需要另一种数据类型…有两个构造函数。一个与某个数据类型的YetAnotherConstructor相同;另一个只会储存一个双人床。我有什么选择

data WantedDataType = ConstructorName1 Double | ConstructorName2 SomeDataType
虽然这会起作用,但这也会让像ConstructorName2$StilloneMore这样的东西变得毫无意义

data WantedDataType = ConstructorName1 Double | ConstructorName2 Yadda Yadda Tittle
同样,这是可行的,但在我看来,这违反了DRY,将内容转换为WantedDataType和SomeDataType可能会很乏味

这是我最喜欢的,但不幸的是,Haskell似乎不支持这种多态性—构造函数不能同时属于两种数据类型

我有什么选择?我应该如何解决这个问题?

这让我觉得YetAnotherConstructor实际上应该是它自己的数据类型:

data SomeDataType = Constructor Blah Blah Blah | OtherConstructor Blah Yadda | YetAnotherConstructor Yadda Yadda Tittle | StillOneMoreConstructor Tittle Tattle Wish Wash
data YetAnotherData = YetAnotherConstructor Yadda Yadda Tittle
data SomeDataType   = Constructor Blah Blah Blah
                    | OtherConstructor Blah Yadda
                    | SomeYetAnotherConstructor {-!-}YetAnotherData
                    -- ! will make this EXACTLY isomorphic to the original 
                    -- but is likely unnecessary 
                    | StillOneMoreConstructor Tittle Tattle Wish Wash
data WantedDataType = ConstructorName1 Double
                    | ConstructorName2 {-!-}YetAnotherData
如果说某个YetAnotherConstructor YetAnotherConstructor和ConstructorName2 YetAnotherData让你很恼火,我想你会认为这会让你回到原点:

{-# LANGUAGE PatternSynonyms #-}

pattern SomeYetAnother :: Yadda -> Yadda -> Tittle -> SomeDataType
pattern SomeYetAnother x y z = SomeYetAnotherConstructor (YetAnotherConstructor x y z)
{-# COMPLETE Constructor, OtherConstructor, SomeYetAnother, StillOneMoreConstructor #-}

pattern WantedYetAnother :: Yadda -> Yadda -> Tittle -> WantedDataType
pattern WantedYetAnother x y z = ConstructorName2 (YetAnotherConstructor x y z)
{-# COMPLETE ConstructorName1, WantedYetAnother #-}
这将使SomeYetAnother和WantedYetAnother像数据构造函数一样完成覆盖率检查、完整的杂注、模式匹配和构造。当您不关心YetAnotherData是它自己的单元这一事实时,可以使用它们来构造/匹配每种类型,如果您想将YetAnotherData作为一个单元来处理,则可以使用底层的SomeYetAnotherConstructor和ConstructorName2构造函数。后者可能对以下情况有用:

someToWantedByYet :: SomeDataType -> Maybe WantedDataType
someToWantedByYet (SomeYetAnotherConstructor y) = Just $ ConstructorName2 y
someToWantedByYet _ = Nothing
wantedToSomeByYet :: WantedDataType -> Maybe SomeDataType
wantedToSomeByYet (ConstructorName2 y) = Just $ SomeYetAnotherConstructor y
wantedToSomeByYet _ = Nothing
这让我觉得YetAnotherConstructor实际上应该是它自己的数据类型:

data SomeDataType = Constructor Blah Blah Blah | OtherConstructor Blah Yadda | YetAnotherConstructor Yadda Yadda Tittle | StillOneMoreConstructor Tittle Tattle Wish Wash
data YetAnotherData = YetAnotherConstructor Yadda Yadda Tittle
data SomeDataType   = Constructor Blah Blah Blah
                    | OtherConstructor Blah Yadda
                    | SomeYetAnotherConstructor {-!-}YetAnotherData
                    -- ! will make this EXACTLY isomorphic to the original 
                    -- but is likely unnecessary 
                    | StillOneMoreConstructor Tittle Tattle Wish Wash
data WantedDataType = ConstructorName1 Double
                    | ConstructorName2 {-!-}YetAnotherData
如果说某个YetAnotherConstructor YetAnotherConstructor和ConstructorName2 YetAnotherData让你很恼火,我想你会认为这会让你回到原点:

{-# LANGUAGE PatternSynonyms #-}

pattern SomeYetAnother :: Yadda -> Yadda -> Tittle -> SomeDataType
pattern SomeYetAnother x y z = SomeYetAnotherConstructor (YetAnotherConstructor x y z)
{-# COMPLETE Constructor, OtherConstructor, SomeYetAnother, StillOneMoreConstructor #-}

pattern WantedYetAnother :: Yadda -> Yadda -> Tittle -> WantedDataType
pattern WantedYetAnother x y z = ConstructorName2 (YetAnotherConstructor x y z)
{-# COMPLETE ConstructorName1, WantedYetAnother #-}
这将使SomeYetAnother和WantedYetAnother像数据构造函数一样完成覆盖率检查、完整的杂注、模式匹配和构造。当您不关心YetAnotherData是它自己的单元这一事实时,可以使用它们来构造/匹配每种类型,如果您想将YetAnotherData作为一个单元来处理,则可以使用底层的SomeYetAnotherConstructor和ConstructorName2构造函数。后者可能对以下情况有用:

someToWantedByYet :: SomeDataType -> Maybe WantedDataType
someToWantedByYet (SomeYetAnotherConstructor y) = Just $ ConstructorName2 y
someToWantedByYet _ = Nothing
wantedToSomeByYet :: WantedDataType -> Maybe SomeDataType
wantedToSomeByYet (ConstructorName2 y) = Just $ SomeYetAnotherConstructor y
wantedToSomeByYet _ = Nothing

一种方法是将YetAnotherConstructor拆分为不同的类型,然后在SomeDataType和WantedDataType中使用。一种方法是将YetAnotherConstructor拆分为不同的类型,然后在SomeDataType和WantedDataType中使用。