我有一个(非常复杂的)数据类型:
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,将内容与WantedDataType
和SomeDataType
之间来回转换可能很繁琐。
data WantedDataType = ConstructorName1 Double | YetAnotherConstructor Yadda Yadda Tittle
这是我最想要的,但是不幸的是,Haskell似乎并不支持这种多态性(构造函数不能同时属于两种数据类型)。
我有什么选择?我该如何解决?
答案 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 #-}
这将使SomeYetAnother
和WantedYetAnother
像数据构造函数一样工作(完成覆盖率检查(COMPLETE
编译指示),模式匹配和构造。当您不关心YetAnotherData
是它自己的单位这一事实时,可以使用它们在每种类型上进行构造/匹配,并且可以在下面的情况下使用基础的SomeYetAnotherConstructor
和ConstructorName2
构造函数您想将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