2

所以 Data.MapdataCast2定义了,这是有道理的,因为它有一个 arity 2 类型的构造函数。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.DataData.Typeable并给定一个已定义的 arity 2 类型构造dataCast2函数(例如Map, 或(,)),是否有可能编写一个dataCast1对部分专业化做正确事情的版本这种类型的构造函数,一次用于一个特定的构造函数,还是一般?

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

4

2 回答 2

1

我不确定这是否是您想要的,但如果不是,它可能会引导您朝着正确的方向前进。它的编写风格与Data.Typeable 库中的 、 和 函数gcast非常gcast1相似。gcast2有关更多详细信息,请参阅“阅读来源,卢克”。

myDataCast1 :: forall c t d e a.(Typeable d, Typeable e) => c (t d a) -> Maybe (c (t e a))
myDataCast1 x = r
   where
     r = case typeOf (getArg x) == typeOf (getArg (fromJust r)) of
           True  -> Just $ unsafeCoerce x
           False -> Nothing
     getArg :: c (t x a) -> x
     getArg = undefined

使用这个函数,你可以,例如写foo

foo :: Typeable d => c (d, a) -> Maybe (c (Int, a))
foo = myDataCast1
于 2010-12-01T04:04:49.857 回答
0

根据本文,实现 dataCast1 的方法是

dataCast1 f = gcast1 f -- for unuary type constructors

或者

dataCast1 f = Nothing -- for non-unary type constructors

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

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

这很烦人,但它确实有效。但也许它不符合您想要实现的目标。

于 2010-12-20T04:32:54.183 回答