仿制药的约束类型

发布于 2025-02-10 16:01:58 字数 448 浏览 0 评论 0原文

我正在尝试将转换为通用类型的YAML。

我实施的简单转换效果很好,但是我想使用他们的show实例,例如data foo = bar | BIZ

我当时想到了像波纹管这样的事情。它正确地捕获了上述类型,但在调用show时失败,因为我无法正确限制它。

instance {-# OVERLAPPING #-} (GToYaml x, GToYaml y) => GToYaml (D1 d (x :+: y)) where
  gToYaml x = string $ pack $ show $ to x

有可能以某种方式限制原始类型具有通用性并显示实例?,还是应该以某种方式处理它?

I'm trying to implement conversion to YAML for Generic types.

The simple conversion I implemented works well, but I would like to use their Show instance for the types like data Foo = Bar | Biz.

I was thinking of something like bellow. It correctly catches the types mentioned above, but fails on invoking the show as I'm not able to properly constraint it.

instance {-# OVERLAPPING #-} (GToYaml x, GToYaml y) => GToYaml (D1 d (x :+: y)) where
  gToYaml x = string $ pack $ show $ to x

Is it possible to somehow constraint for original type to have Generic and Show instances? Or it should be handled somehow differently?

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

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

发布评论

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

评论(1

蒲公英的约定 2025-02-17 16:01:58

据推测,原始类型类似于

class ToYaml x where
  toYaml :: x -> Yaml

假设我们定义此辅助数据类型和Typeclass:

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE ScopedTypeVariables #-}
import Data.Proxy
import GHC.Generics

data HowToConvertToYaml = NormalCase | SpecialCase

class ToYaml' (how :: HowToConvertToYaml) x where
  toYaml' :: Proxy how -> x -> Yaml

HowtoconvertToyAml被用作 datakind ,向toyml':是否提供一条额外信息我们是否在特殊情况下。这使我们能够为每种情况定义不同的实例:

instance Show x => ToYaml' SpecialCase x where
   toYaml' _ = undefined

instance (Generic x, GToYaml (Rep x)) => ToYaml' NormalCase x where
   toYaml' _ = undefined

问题是我们要使用fotaml,而不是toyaml'。我们需要一种方法来自动计算每种类型的howtoconvertToyAml,然后在toyaml'上进行toyaml实例委托。

我们可以使用一个类型的家庭:

type family FindHowToConvertToYaml rep :: HowToConvertToYaml where
  FindHowToConvertToYaml (D1 _ (_ :+: _)) = SpecialCase
  FindHowToConvertToYaml _ = NormalCase

toyaml根据toyaml'是:

instance (Generic x, ToYaml' (FindHowToConvertToYaml (Rep x)) x) => ToYaml x where
  toYaml = toYaml' (Proxy @(FindHowToConvertToYaml (Rep x)))

Presumably, the original typeclass is something like

class ToYaml x where
  toYaml :: x -> Yaml

Suppose we define this auxiliary datatype and typeclass:

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE ScopedTypeVariables #-}
import Data.Proxy
import GHC.Generics

data HowToConvertToYaml = NormalCase | SpecialCase

class ToYaml' (how :: HowToConvertToYaml) x where
  toYaml' :: Proxy how -> x -> Yaml

HowToConvertToYaml is being used as a DataKind, to provide one piece of extra information to ToYaml': whether we are in the special case or not. This allows us to define different instances for each case:

instance Show x => ToYaml' SpecialCase x where
   toYaml' _ = undefined

instance (Generic x, GToYaml (Rep x)) => ToYaml' NormalCase x where
   toYaml' _ = undefined

The problem is that we want to use ToYaml, not ToYaml'. We need a way to automatically compute the HowToConvertToYaml for each type, and then make the ToYaml instance delegate on the ToYaml' one.

We can use a type family:

type family FindHowToConvertToYaml rep :: HowToConvertToYaml where
  FindHowToConvertToYaml (D1 _ (_ :+: _)) = SpecialCase
  FindHowToConvertToYaml _ = NormalCase

And ToYaml in terms of ToYaml' would be:

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