为不同的类型类实例处理不同的参数类型

时间:2018-04-18 09:27:30

标签: haskell typeclass

我有一个类型类C.

class C a where
  changeProperty :: a -> ??? -> a

C有两个(或更多)实例

data A = A AProperty X
data B = B BProperty Y
instance C A where
   changeProperty (A _ x) ap = A ap x
instance C B where
   changeProperty (B _ y) bp = B bp y

bp和ap是不同类型的。 AProperty仅与A兼容,BProperty仅与B兼容。是否可以为类型签名或其他允许方法changeProperty仅接受这些组合的解决方案制作一些?我能够想到的唯一选项是将方法完全分开(在本例中为changeAProperty和changeBProperty),或者要求我使AProperty和BProperty成为相同的类型,这允许无效的组合,如A与BProperty。理想情况下,我希望有一个属性类,其中AProperty和BProperty是实例,但我不知道如何做到这一点并避免无效组合。

编辑:此问题的上下文是用于构建MD模拟分子的脚本。 A,B等是原子之间的连接。例如,A将是一个键,包含AProperty中的这个键的参数和X中涉及的原子.B将是一个角度,BP将包含与该角度相关的参数,Y是原子等等。

3 个答案:

答案 0 :(得分:4)

我喜欢其他解决方案的普遍性。但在这种特殊情况下,我想提出一个无类别的解决方案。

data Meta properties parameters = Meta properties parameters

changeProperty :: Meta props params -> props -> Meta props params
changeProperty (Meta props params) props' = Meta props' params

type A = Meta AProperty X
type B = Meta BProperty Y

这种事情是非常普遍的需要;另请参阅this question,了解实现此目的的记录访问器方式的简要概述,以及为减少与记录访问器相关的痛苦而建立的库。

答案 1 :(得分:3)

我估计你想要这个:

{-# LANGUAGE TypeFamilies #-}
class C a where
  type CProperty a :: *
  changeProperty :: a -> CProperty a -> a

data A = A AProperty X
data B = B BProperty Y
instance C A where
   type CProperty A = AProperty
   changeProperty (A _ x) ap = A ap x
instance C B where
   type CProperty B = BProperty
   changeProperty (B _ y) bp = B bp y

...或者,如果确实AProperty仅适用于A,则具有功能依赖性的MPTC解决方案

{-# LANGUAGE FunctionalDependencies #-}

class C a ap | ap -> a, a -> ap where
    changeProperty :: a -> ap -> a

data X = X
data Y = Y

data AProperty = AProperty
data BProperty = BProperty

data A = A AProperty X
data B = B BProperty Y

instance C A AProperty where
    changeProperty (A _ x) ap = A ap x
instance C B BProperty where
    changeProperty (B _ y) bp = B bp y

正如您已经注意到的,这也是在没有函数依赖性的情况下编译的,但是在实践中使用它通常很麻烦,因为对于所有编译器都知道,A可以有任何其他属性和AProperty可以应用于任何其他类型,因此您最终必须为类型检查器键入大量的explicits约束。

答案 2 :(得分:1)

正如Willem Van Onsem所提到的,可以使用多参数类型。

{-# LANGUAGE MultiParamTypeClasses #-}
class C a ap where
    changeProperty :: a -> ap -> a

data X = X
data Y = Y

data AProperty = AProperty
data BProperty = BProperty

data A = A AProperty X
data B = B BProperty Y
instance C A AProperty where
    changeProperty (A _ x) ap = A ap x
instance C B BProperty where
    changeProperty (B _ y) bp = B bp y

至于它是否是我不知道的最佳解决方案。