Generics Data.Data——为arity 2类型构造函数生成dataCast1(部分专用)

Generics Data.Data——为arity 2类型构造函数生成dataCast1(部分专用),generics,haskell,scrap-your-boilerplate,Generics,Haskell,Scrap Your Boilerplate,因此Data.Map定义了dataCast2,这很有意义,因为它有一个arity2类型的构造函数dataCast1默认为const NothingdataCast2很容易定义为gcast2 供参考: class Typeable a => Data a where dataCast1 :: Typeable1 t => (forall d. Data d => c (t d)) -> Maybe (c a) dataCast2 :: Typeable2 t

因此Data.Map定义了
dataCast2
,这很有意义,因为它有一个arity2类型的构造函数
dataCast1
默认为
const Nothing
dataCast2
很容易定义为
gcast2

供参考:

class Typeable a => Data a where
    dataCast1 :: Typeable1 t => (forall d. Data d => c (t d)) -> Maybe (c a)
    dataCast2 :: Typeable2 t => (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c a)
    ...

gcast1 :: (Typeable1 t, Typeable1 t') => c (t a) -> Maybe (c (t' a))
gcast2 :: (Typeable2 t, Typeable2 t') => c (t a b) -> Maybe (c (t' a b))
手头的问题是:给定
Data.Data
Data.Typeable
等中的所有内容,并给定定义了
dataCast2
的arity2类型构造函数(例如,
Map
,或
(,)
),是否有可能编写一个版本的
dataCast1
,对这种类型的构造函数的部分专门化做正确的事情,一次针对一个特定的构造函数,或者一般来说


直觉上,我认为应该有一个好的解决方案,但我最初的几次尝试失败了。

我不确定这是否是你想要的,但如果不是,它可能会引导你朝着正确的方向前进。它的编写风格与Data.Typeable库中的
gcast
gcast1
gcast2
函数非常相似。欲知更多详情,请阅读来源Luke

使用此函数,您可以编写
foo

foo :: Typeable d => c (d, a) -> Maybe (c (Int, a))
foo = myDataCast1
根据这一点,实现dataCast1的方法如下

dataCast1 f = gcast1 f -- for unuary type constructors

他们没有说这是实现它的唯一方法,但可能是这样。也许值得问问作者们?我认为核心问题是我们不能部分应用类型构造函数。e、 g.以下是不可能的

data T a b = ...

instance Typeable a => Data (T Int) where
   dataCast1 f = ...
GHC会抱怨T没有应用到足够的类型参数

不过我可以想出一个解决办法。我们定义了一个新类型

newtype PairInt a = PairInt (Int, a) deriving Typeable

instance (Typeable a, Data a) => Data (PairInt a) where
  dataCast1 f = gcast1 f

这很烦人,但它确实起作用了。但这可能与您想要实现的目标不符。

这看起来是一个有趣的问题,但我想我需要更多的背景知识。首先是一个问题。“对于这种类型的构造函数的部分应用程序,做正确的事情”到底是什么意思?类型构造函数可以在类或实例声明的头部显示为部分应用,但在其他任何地方,它们必须显示为完全应用。@Sean说得对。我把它改为“部分专业化”。关键是能够调用
myDataCast1
的结果是
Maybe(c(Int,a))
就像调用
dataCast1的结果是
Maybe(c(Maybe a))
。close,但no:-)。棘手的一点是匹配dataCast如何生成任何类型的
DataA=>Maybe(CA)
——也就是说,它的结果除了
c
之外没有任何类型构造函数。要了解为什么这是必要的,试着玩弄<代码>数据。泛型。别名< /代码>,并考虑为什么<代码> Ext1q不能简单地写在代码> GCAST 1/代码>中,而不是<代码> DATACAST1/<代码>。
data T a b = ...

instance Typeable a => Data (T Int) where
   dataCast1 f = ...
newtype PairInt a = PairInt (Int, a) deriving Typeable

instance (Typeable a, Data a) => Data (PairInt a) where
  dataCast1 f = gcast1 f