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

gaa*_*kam 1 constructor haskell types

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

data SomeDataType = Constructor Blah Blah Blah | OtherConstructor Blah Yadda | YetAnotherConstructor Yadda Yadda Tittle | StillOneMoreConstructor Tittle Tattle Wish Wash
Run Code Online (Sandbox Code Playgroud)

现在,我发现自己想要另一种数据类型…具有两个构造函数。之一将是相同YetAnotherConstructorSomeDataType; 另一个只会存储一个Double。我有什么选择?

data WantedDataType = ConstructorName1 Double | ConstructorName2 SomeDataType
Run Code Online (Sandbox Code Playgroud)

虽然这可行,但也可以允许ConstructorName2 $ StillOneMoreConstructor tittle tattle wish wash没有意义的东西。

data WantedDataType = ConstructorName1 Double | ConstructorName2 Yadda Yadda Tittle
Run Code Online (Sandbox Code Playgroud)

再说一次,这是可行的,但在我看来,这违反了DRY的规定,将东西往返于WantedDataType和转换可能很乏味SomeDataType

data WantedDataType = ConstructorName1 Double | YetAnotherConstructor Yadda Yadda Tittle
Run Code Online (Sandbox Code Playgroud)

这就是我最想要的,但是不幸的是,Haskell似乎并不支持这种多态性(构造函数不能同时属于两种数据类型)。

我有什么选择?我该如何解决?

HTN*_*TNW 9

这使我认为YetAnotherConstructor实际上是“应该”为其自己的数据类型:

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
Run Code Online (Sandbox Code Playgroud)

如果您不喜欢说SomeYetAnotherConstructor (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 #-}
Run Code Online (Sandbox Code Playgroud)

这将使数据构造器发挥作用,SomeYetAnotherWantedYetAnother像数据构造器一样工作(完成覆盖率检查(COMPLETE编译指示),模式匹配和构造)。当您不关心它YetAnotherData是自己的单元时,可以使用它们在每种类型上进行构造/匹配,如果要将“ 单元” 视为一个单元,则可以使用基础SomeYetAnotherConstructorConstructorName2构造函数YetAnotherData。后者可能对例如

someToWantedByYet :: SomeDataType -> Maybe WantedDataType
someToWantedByYet (SomeYetAnotherConstructor y) = Just $ ConstructorName2 y
someToWantedByYet _ = Nothing
wantedToSomeByYet :: WantedDataType -> Maybe SomeDataType
wantedToSomeByYet (ConstructorName2 y) = Just $ SomeYetAnotherConstructor y
wantedToSomeByYet _ = Nothing
Run Code Online (Sandbox Code Playgroud)