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

发布于 2024-10-05 16:09:56 字数 891 浏览 5 评论 0原文

因此 Data.Map 定义了 dataCast2,这是有道理的,因为它有一个 arity 2 类型构造函数。 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 => (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 版本对于这种类型构造函数的部分特化,无论是一次针对一个特定的构造函数,还是一般情况下,正确的做法是什么?

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

So Data.Map has dataCast2 defined, which makes sense, as it has an arity 2 type constructor. dataCast1 defaults to const Nothing. dataCast2 is easily defined as gcast2.

For reference:

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))

The question at hand is this: given everything in Data.Data, Data.Typeable, etc., and given an arity 2 type constructor for which dataCast2 is defined (say, Map, or (,) ), is it possible to write a version of dataCast1 that does the right thing for a partial specialization of this type constructor, either for one specific constructor at a time, or in general?

Intuitively, I think there should be a good solution, but my first few tries crashed and burned.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

游魂 2024-10-12 16:09:56

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

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

I'm not sure if this is what you want, but it might steer you in the right direction if it's not. It is written in a very similar style to the gcast, gcast1, and gcast2 functions in the Data.Typeable library. For more details, "read the source, Luke".

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

Using this function you can, for instance write foo

foo :: Typeable d => c (d, a) -> Maybe (c (Int, a))
foo = myDataCast1
少女七分熟 2024-10-12 16:09:56

根据这篇论文的方法Implement dataCast1 要么是 as

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

这很烦人,但它可以完成工作。但也许它不符合您想要实现的目标。

According to this paper the way to implement dataCast1 is either as

dataCast1 f = gcast1 f -- for unuary type constructors

or

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

They haven't said that this is the only way to implement it, but it might be the case. Perhaps it's worth asking the authors? I think the core problem is that we can't partially apply type constructors. e.g. the following is not possible

data T a b = ...

instance Typeable a => Data (T Int) where
   dataCast1 f = ...

GHC will complain that T has not been applied to enough type arguments.

I can think of a work-around though. We define a newtype

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

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

It's pretty annoying but it does the job. But perhaps it doesn't fit with what you're trying to achieve.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文