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

时间:2019-05-05 21:30:39

标签: haskell types constructor

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

data SomeDataType = Constructor Blah Blah Blah | OtherConstructor Blah Yadda | YetAnotherConstructor Yadda Yadda Tittle | StillOneMoreConstructor Tittle Tattle Wish Wash

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

data WantedDataType = ConstructorName1 Double | ConstructorName2 SomeDataType

虽然这行得通,但也会允许ConstructorName2 $ StillOneMoreConstructor tittle tattle wish wash之类的东西,这毫无意义。

data WantedDataType = ConstructorName1 Double | ConstructorName2 Yadda Yadda Tittle

同样,这是可行的,但是在我看来,这违反了DRY,将内容与WantedDataTypeSomeDataType之间来回转换可能很繁琐。

data WantedDataType = ConstructorName1 Double | YetAnotherConstructor Yadda Yadda Tittle

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

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

1 个答案:

答案 0 :(得分: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

如果让您说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 #-}

这将使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