麻烦重构当前类型(可能与GADT / Type Families相关)

时间:2015-01-29 11:37:00

标签: haskell types refactoring gadt

我有这样的类型:

-- There are codes
newtype ICode = ICode { fromICode :: String }
newtype RCode = RCode { fromRCode :: String }
data DCode = DCode1 | DCode2 | DCode3

-- There are locations described by type and code.
-- Current implementation looks like this:
data Location = LocType1 ICode
              | LocType2 ICode
              | LocType3 RCode
              | LocType4 DCode

我想重构这些类型以解决当前实施中存在的一些问题。

使用QuickCheck Arbitrary和Aeson的FromJSON个实例以及另外一个函数,很容易证明我之后的属性。 生成正确的测试数据需要前3个属性,第4个属性需要 实现业务逻辑。

我希望能够:

  1. 制作所有代码类型的任意实例,例如

        instance Arbitrary ICode where
          arbitrary = ...
        -- same with RCode and DCode
    
  2. 制作Arbitrary类似Location1 ICode类型的实例(它明显不同于当前的实施方式,而且是我试图解决的问题),它描述的确切组合位置类型和代码类型。 Location1 ICode只能包含ICode个可能值的子集,因此我必须确保这一点。

  3. 制作所有可能类型的FromJSON个实例,内容如下:

    instance FromJSON (Location a) where
      parseJSON = ...
    

    根据它们的值,需要对一些json对象进行反序列化。

  4. 某些功能必须仅适用于一种位置类型。它在当前的实现中非常不方便,因为我必须使用不完整的函数或不正确的返回类型,例如Maybe。我希望能够做到这样的事情:

    location1IncludedInArbitraryLocation :: LocType1 -> Location a -> Bool
    location1IncludedInArbitraryLocation l = ...
    
  5. 我认为解决方案位于GADT /数据系列领域的某个地方,但我对这种类型的fu并不是很流利。如果有几种方法可以解决这个问题,哪一个更容易进行类型检查/以后使用?

1 个答案:

答案 0 :(得分:2)

3和4似乎不兼容。这听起来像一个“后备”机制:如果没有更多特定实例可用,请使用此实例。您可以使用OverlappingInstances获得此功能,但我似乎总是遇到麻烦。值得一试,我想。

至于你的其他问题,你似乎希望Location成为GADT。

data LocType = Type1 | Type2 | Type3 | Type4

data Location :: LocType -> * where
    LocType1 :: ICode -> Location Type1
    LocType2 :: ICode -> Location Type2
    LocType3 :: RCode -> Location Type3
    LocType4 :: DCode -> Location Type4

然后你可以很容易地做到:

location1IncludedInArbitraryLocation :: Location Type1 -> Location t -> Bool
location1IncludedInArbitraryLocation (LocType1 icode) l = ...

此处不需要定义任何其他情况,因为没有其他构造函数可以很好地输入。

我希望这足以让你开始玩。

(需要DataKindsKindSignaturesGADTs