量化约束与(封闭)类型族

2023-11-26

我正在尝试使用这篇博文的方法是在不悬而未决的情况下获取更高级的数据Identity简单情况的函子与量化约束推导一起:

{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE QuantifiedConstraints, StandaloneDeriving, UndecidableInstances #-}
module HKD2 where

import Control.Monad.Identity

type family HKD f a where
    HKD Identity a = a
    HKD f        a = f a

data Result f = MkResult
    { foo :: HKD f Int
    , bar :: HKD f Bool
    }

deriving instance (forall a. Show a => Show (HKD f a)) => Show (Result f)

这会导致令人恼火的自相矛盾的错误消息:

无法推断Show (HKD f a)从上下文来看:forall a. Show a => Show (HKD f a)

有没有一种方法可以做到这一点而不需要冗长地做

deriving instance (Show (HKD f Int), Show (HKD f Bool)) => Show (Result f)

?


长话短说,博士,要点:https://gist.github.com/Lysxia/7f955fe5f2024529ba691785a0fe4439

样板约束

首先,如果问题是关于避免重复的代码,那么这主要是仅通过泛型来解决,而不需要QuantifiedConstraints。约束条件(Show (HKD f Int), Show (HKD f Bool))可以从通用表示计算Rep (Result f)。 generic-data 包(免责声明:我写的)实现了这一点:

data Result f = MkResult (HKD f Int) (HKD f Bool)
  deriving Generic

-- GShow0 and gshowsPrec from Generic.Data
instance GShow0 (Rep (Result f)) => Show (Result f) where
  showsPrec = gshowsPrec

or with DerivingVia:

-- Generically and GShow0 from Generic.Data
deriving via Generically (Result f) instance GShow0 (Rep (Result f)) => Show (Result f)

类型族的量化约束

尽管如此,约束(Show (HKD f Int), Show (HKD f Bool))可能由于各种原因不太理想。这QuantifiedConstraints扩展似乎提供了更自然的约束forall x. Show (HKD f x):

  • 这将需要元组(Show (HKD f Int), Show (HKD f Bool));

  • 与该元组相反,当记录变大时,它的大小不会膨胀,并且不会泄漏Result因为它们可能会发生变化。

不幸的是,这个约束实际上并不完善。以下 GHC 问题详细讨论了该问题:https://gitlab.haskell.org/ghc/ghc/issues/14840我还不明白所有的原因,但简而言之:

  • 由于理论和实践的原因,在可预见的未来,量化约束不会直接适用于类型族;

  • 但对于大多数用例都有一个解决方法。

量化约束应被视为一种“局部约束”instance”。一般规则是类型族不允许出现在任何实例的头部(“实例头部”=HEAD在下面的instance ... => HEAD where). So forall a. Show (HKD f a)(被视为“本地”instance Show (HKD f a))是非法的。

量化约束走私者

以下解决方案归功于Icelandjack(来源:此评论来自之前链接的票证;也感谢 Ryan Scott 的转发。)

我们可以定义另一个类,它相当于Show (HKD f a):

class    Show (HKD f a) => ShowHKD f a
instance Show (HKD f a) => ShowHKD f a

Now forall x. ShowHKD f x是一种法律约束,在道德上表达了预期的forall x. Show (HKD f x)。但如何使用它并不明显。例如,以下代码片段无法进行类型检查(注意:我们可以轻松忽略歧义问题):

showHKD :: forall f. (forall x. ShowHKD f x) => HKD f Int -> String
showHKD = show

-- Error:
-- Could not deduce (Show (HKD f Int)) from the context (forall x. ShowHKD f x)

这是违反直觉的,因为ShowHKD f x相当于Show (HKD f x)当然可以实例化为Show (HKD f Int)。那么为什么会被拒绝呢?约束求解器向后推理:使用show首先需要一个约束Show (HKD f Int),但求解器立即卡住了。它看到forall x. ShowHKD f x在上下文中,但求解器没有任何线索知道它应该实例化x to Int。您应该想象,此时约束求解器不知道之间的任何关系Show and ShowHKD。它只是想要一个Show约束,并且上下文中没有约束。

我们可以通过如下方式帮助约束求解器,通过使用所需的实例化来注释函数体ShowHKD f x, here ShowHKD f Int:

showHKD :: forall f. (forall x. ShowHKD f x) => HKD f Int -> String
showHKD = show :: ShowHKD f Int => HKD f Int -> String

这个注释provides约束条件ShowHKD f Int对身体show,这反过来又使超类可用Show (HKD f Int) so show可以立刻得到满足。另一边是注释requires约束条件ShowHKD f Int从它的上下文来看,它提供了forall x. ShowHKD f x。那些限制match,这导致约束求解器实例化x适当地。

具有量化约束的导出显示

有了这个,我们就可以实现Show具有量化约束,使用泛型填充正文,并使用一些注释来实例化量化约束,(ShowHKD f Int, ShowHKD f Bool):

instance (forall a. Show a => ShowHKD f a) => Show (Result f) where
  showsPrec = gshowsPrec :: (ShowHKD f Int, ShowHKD f Bool) => Int -> Result f -> ShowS

和以前一样,这些约束可以使用泛型自动化,因此在此实现中从一种类型到另一种类型的唯一变化是名称Result:

instance (forall a. Show a => ShowHKD f a) => Show (Result f) where
  showsPrec = gshowsPrec :: ShowHKDFields f (Rep (Result HKDTag)) => Int -> Result f -> ShowS

-- New definitions: ShowHKDFields and HKDTag; see gist at the end.

只要多一点努力,我们就可以拥有DerivingVia too:

deriving via GenericallyHKD Result f instance (forall a. Show a => ShowHKD f a) => Show (Result f)

-- New definition: GenericallyHKD; see gist.

完整要点:https://gist.github.com/Lysxia/7f955fe5f2024529ba691785a0fe4439

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

量化约束与(封闭)类型族 的相关文章

  • 使用 Template Haskell 生成函数

    是否可以使用 Template Haskell 定义函数 例如 convertStringToValue String gt Int convertStringToValue three 3 convertStringToValue fou
  • 如何在 Windows 7 中配置 cabal?

    我已经在Windows 7中安装了Haskell Platform 2012 我在控制台中编写cabal update我收到消息说有新版本的阴谋集团 我写的cabal install cabal install 安装完成后 它告诉我 cab
  • 在 Haskell 中提升 State monad 中的值

    我正在 Haskell 中编写一个数独生成器 求解器作为学习练习 My solve函数接受一个UArray但返回一个State Int UArray 这样它也可以返回解决问题时发现的最大难度级别 到目前为止 这是我的功能 仍处于实验性的早期
  • Haskell 中的异构多态性(正确方法)

    让一个模块来抽象Area操作 错误的定义 class Area someShapeType where area someShapeType gt Float module utilities sumAreas Area someShape
  • Haskell:Where 与 Let

    我是 Haskell 的新手 我很困惑Where vs Let 它们似乎都提供了相似的目的 我读过一些比较Where vs Let但我很难辨别何时使用它们 有人可以提供一些背景信息或者一些示例来说明何时使用其中一种而不是另一种吗 哪里与让
  • 如何在 Haskell 中获得列表的中间位置?

    我刚刚开始使用 Haskel 学习函数式编程 我正在慢慢度过Erik Meijer 在 Channel 9 的讲座 http channel9 msdn com shows Going Deep Lecture Series Erik Me
  • 函数式编程是否需要新的命名约定?

    我最近开始使用 Haskell 学习函数式编程 并在 Haskell 官方 wiki 上发现了这篇文章 如何阅读哈斯克尔 http www haskell org haskellwiki How to read Haskell What t
  • 显示未定义的实例

    可以采取任何措施来为未定义的值定义 Show 实例吗 也许存在一些 GHC 扩展 我想要这样的东西 gt print 1 undefined 1 undefined 根据Haskell 2010 报告 第 9 章 http www hask
  • 用parsec解析递归数据

    import Data Attoparsec Text Lazy import Data Text Lazy Internal Text import Data Text Lazy pack data List a Nil Cons a L
  • 将系统命令的结果绑定到 Haskell 中的变量

    如何在 Haskell 中运行系统命令and将其结果 即标准输出 绑定到变量 在伪 Haskell 中 我正在寻找类似以下内容的内容 import System Process main do output lt callCommand e
  • 为什么 Haskell 中有协函子和逆变函子的区别,而范畴论却没有区别?

    这个答案是从范畴论的角度来看的 https math stackexchange com a 661989 72174包括以下语句 事实是 协函子和逆变函子之间没有真正的区别 因为每个函子只是一个协变函子 More in details a
  • Haskell 中的实例声明

    我有这两个功能 primes sieve 2 where sieve p xs p sieve x x lt xs x mod p gt 0 isPrime number number 1 null x x lt takeWhile x g
  • 将数据类型设置为 Kind * -> * 这不是函子

    布伦特 约尔吉类型分类百科全书 https www haskell org haskellwiki Typeclassopedia给出以下练习 举一个类型的例子 gt 不能将其制成 的实例Functor 不使用undefined 请告诉我什
  • Haskell scala 互操作性

    我是 Scala 初学者 来自面向对象范式 在了解 Scala 的函数式编程部分时 我被引导到 Haskell 纯函数式编程语言 探索 SO 问题答案 我发现 Java Haskell 具有互操作性 我很想知道 Scala Haskell
  • Haskell:是的,没有类型类。为什么是整数?

    我有一个关于 GHCi 如何假定整数类型的问题 我正在阅读 Learn you a Haskell 是 否类型的课程 如果您想阅读全文 这里有一个链接 http learnyouahaskell com making our own typ
  • 将 num 的签名键入 double?

    我才刚刚开始为你学习 Haskell 以获得伟大的好处 并且我在类型类方面遇到了一些麻烦 我想创建一个接受任何数字类型并强制其为双精度的函数 我的第一个想法是定义 numToDouble Num gt Double 但我认为这不起作用 因为
  • Haskell - 用防护罩替换外壳

    我想知道在这部分代码中是否可以用守卫替换 case 语句 firstFunction String gt Maybe MyType secondFunction MyType gt Integer myFunction String gt
  • Haskell 中的分类结构

    Hask通常被认为是一个范畴 其对象是类型 态射是函数 然而 我看到 Conor McBride pigworker 警告不要使用Hask多次 1 https stackoverflow com a 45905082 474311 2 ht
  • “Eta减少”并不总是在Haskell中举行?

    我发现我可以说 LANGUAGE RankNTypes f1 forall b b gt b gt forall c c gt c f1 f id f HLint 告诉我我可以在这里做 Eta 减少 但是 f2 forall b b gt
  • Haskell 入门

    这个问题的答案是社区努力 help privileges edit community wiki 编辑现有答案以改进这篇文章 目前不接受新的答案或互动 几天来 我一直试图理解 Haskell 中的函数式编程范例 我通过阅读教程和观看截屏视频

随机推荐

  • 使用 DbContext.Database.SqlQuery 在 EntityFramework 中进行预加载

    在 EF 4 中 我可以通过编写 sql 来预先加载导航属性吗DbContext Database SqlQuery or DbContext Set
  • 在 Mac OS 10.11 (El Capitan) 上使用 pfctl 转发端口

    我目前正在测试我的开发环境是否可以在即将推出的新 Mac OS 10 11 上运行 以及是否可以在发布后立即升级 在我的测试机器上 我当前正在运行 Beta Preview 3 一切似乎都运行良好 我只能得到pfctl转发我的端口 我使用
  • Angular 模板中的 Javascript 广告

    我正在尝试在 Angular 模板中呈现 Javascript 广告 但它不会显示 当他们将 Javascript 附加到 head 标签时 我找到了一些解决方案 但我希望将广告放置在我的 Html 正文内 中 这是一个笨蛋 https p
  • TestNG 选项未显示在 Eclipse 的 RunAs 选项中

    我在 Eclipse IDE 中使用 Maven 项目 并添加了一个 testng 依赖项
  • 如何使用网络浏览器在链接列表中导航?

    我有一个网址列表 我需要导航它们 如何确保每个 url 都会调用 DocumentCompleted 事件 我已经尝试创建许多线程并尝试使用单个线程 但应用程序仍然没有为每个 url 触发事件 DocumentCompleted 有没有办法
  • 如何在 Release() 上释放 NET COM 互操作对象

    我有一个用托管代码 C CLI 编写的 COM 对象 我在标准 C 中使用该对象 当 COM 对象被释放时 如何强制立即调用 COM 对象的析构函数 如果不可能 请调用 I have Release 在我的 COM 对象上调用 MyDisp
  • 通过 HTTPS 投放广告

    我知道不存在愚蠢的问题 但这是 您可以通过 adsense 或其他完全支持 https 的网站上的其他方式提供基于上下文的广告吗 Update 我们更新了 AdSense 广告代码 现在支持通过安全超文本传输 协议 HTTPS 网页上的安全
  • 使用jquery获取keyup位置[重复]

    这个问题在这里已经有答案了 可能的重复 如何获取文本区域中的插入符位置 如果我在 html textarea 控件中的任何位置键入 我需要获取 keyup 事件的当前位置 例如 Welcome to jQuery 所以我在 欢迎 之后有 表
  • 将本体与 Protege-OWL API 合并

    我使用 protege 创建了两个本体 并保存为 A owl B owl 我知道protege 4 0可以合并很多本体 我想使用protege owl API将本体A owl和B owl合并到C owl 但我不知道该怎么做 你可以帮帮我吗
  • 以最少的配置使用 Unity

    在工作中 我们经常使用Unity 它的工作非常出色 但是您使用它的次数越多 您的配置文件就会增长得越多 运行时问题也会增加得越多 并且您必须为每个测试项目重新创建统一配置的次数就越多 因此 我们最终得到了一个巨大的统一配置部分 必须在多个项
  • 在 Posix 中如何使用 dev_t 类型?

    我追求的是这种类型的含义以及什么接口可以使用它 Posix 规范中解释说dev t用于设备 ID 但是 对于路径所描述的任何对象 可以是文件 目录 fifo 或物理设备 来说 设备 id 意味着什么 例如 调用stat 应为您提供一个包含此
  • 将类添加到单击的元素

    我正在尝试向单击的元素添加一个类 有多个具有唯一 ID 的元素 因此我 不知道 元素的 ID 是什么 我可以使用以下代码的修改版本来实现此目的吗 Jquery document ready function this on click fu
  • 我如何在 iOS 5 中使用 CMDeviceMotion 获取设备的标题

    我正在使用陀螺仪开发 AR 应用程序 我使用了苹果代码示例公园 它使用旋转矩阵来计算坐标的位置 而且效果非常好 但现在我正在尝试实现一个 雷达 我需要根据设备航向来旋转它 我正在使用 CLLocationManager 标题 但它不正确 问
  • Angular ViewChildren 不会立即看到 ngFor 中的所有子级

    我有一个奇怪的行为 ViewChildren 对应于 ngFor 生成的子组件 ViewChildren 查询没有看到元素在数组中停留了很长时间 我所有的代码都在Plunker 打开控制台后查看 这是我的主要组成部分 Component s
  • XMLHttp请求超时

    如何为以下脚本添加超时 我希望它将文本显示为 时间到 var bustcachevar 1 bust potential caching of external pages after initial request 1 yes 0 no
  • Redis 获取大字符串很慢

    我是 Redis 的新手 所以如果这是一个愚蠢的问题 我深表歉意 我使用 Django 和 Redis 作为缓存 我正在腌制大约 200 个对象的集合并将其存储在 Redis 中 当我从 Redis 请求集合时 Django 调试工具栏通知
  • 带有固定包装器的引导网格 - 防止列堆叠

    正如标题所示 我正在尝试使用带有固定包装器的 Bootstrap 3 网格系统 但是 当我调整浏览器的大小时 即使包装器保持相同的大小 列也会堆积起来 顺便说一句 我正在使用版本 3 以便在移植网站后可以转向响应式布局 这是巨大的 而且我独
  • 使用 Snapshot 和 ParamMap 的 Angular Mock ActivatedRoute

    我正在使用这个 来自here constructor private heroService HeroService private activatedRoute ActivatedRoute ngOnInit const heroId t
  • 如何使用 JBoss 4.2.3 以编程方式找出我的 jboss 服务器正在侦听哪个端口?

    例如 如何确定我的简单 JBoss 4 2 3 服务器正在侦听端口 8080 这是我能达到的最接近的结果 但这不起作用 MBeanServerConnection server MBeanServerConnection new Initi
  • 量化约束与(封闭)类型族

    我正在尝试使用这篇博文的方法是在不悬而未决的情况下获取更高级的数据Identity简单情况的函子与量化约束推导一起 LANGUAGE TypeFamilies LANGUAGE QuantifiedConstraints Standalon