在没有 unsafeCoerce 的情况下兼顾存在主义

2024-04-16

最近我一直在研究这种类型,我理解它是自由分配函子的编码(有关切线背景,请参阅这个答案 https://stackoverflow.com/a/56822105/2751851):

data Ev g a where
    Ev :: ((g x -> x) -> a) -> Ev g a

deriving instance Functor (Ev g)

存在构造函数确保我只能使用Ev g通过提供多态提取器forall x. g x -> x,并且自由构造的升降功能可以被赋予兼容类型:

runEv :: Ev g a -> (forall x. g x -> x) -> a
runEv (Ev s) f = s f

evert :: g a -> Ev g a
evert u = Ev $ \f -> f u

revert :: Distributive g => Ev g a -> g a
revert (Ev s) = s <$> distribute id

然而,在尝试给予时存在困难Ev g a Distributive实例。鉴于Ev g最终只是一个具有奇怪参数类型的函数,人们可能希望只是线程distribute对于函数(相当于(??) :: Functor f => f (a -> b) -> a -> f b from lens http://hackage.haskell.org/package/lens-4.17.1/docs/Control-Lens-Lens.html#v:-63--63-,并且不以任何方式检查参数类型)通过Ev包装:

instance Distributive (Ev g) where
    distribute = Ev . distribute . fmap (\(Ev s) -> s)

然而,这不起作用:

Flap3.hs:95:53: error:
    • Couldn't match type ‘x’ with ‘x0’
      ‘x’ is a rigid type variable bound by
        a pattern with constructor:
          Ev :: forall (g :: * -> *) x a. ((g x -> x) -> a) -> Ev g a,
        in a lambda abstraction
        at Flap3.hs:95:44-47
      Expected type: (g x0 -> x0) -> a
        Actual type: (g x -> x) -> a
    • In the expression: s
      In the first argument of ‘fmap’, namely ‘(\ (Ev s) -> s)’
      In the second argument of ‘(.)’, namely ‘fmap (\ (Ev s) -> s)’
    • Relevant bindings include
        s :: (g x -> x) -> a (bound at Flap3.hs:95:47)
   |
95 |     distribute = Ev . distribute . fmap (\(Ev s) -> s) 
   |                                                     ^
Failed, no modules loaded.

GHC 反对重新包装存在主义,尽管我们在展开和重新包装之间没有做任何不当的事情。我发现的唯一出路就是诉诸unsafeCoerce:

instance Distributive (Ev g) where
    distribute = Ev . distribute . fmap (\(Ev s) -> unsafeCoerce s)

或者,以更谨慎的方式拼写它:

instance Distributive (Ev g) where
    distribute = eevee . distribute . fmap getEv
        where
        getEv :: Ev g a -> (g Any -> Any) -> a
        getEv (Ev s) = unsafeCoerce s
        eevee :: ((g Any -> Any) -> f a) -> Ev g (f a)
        eevee s = Ev (unsafeCoerce s)

是否可以在不使用的情况下解决这个问题unsafeCoerce?还是真的没有其他办法了?

附加说明:

  • 我相信Ev是我可以给出的最正确的构造类型,尽管我很高兴被证明是错误的。我所有将量词转移到其他地方的尝试都会导致需要unsafeCoerce其他地方或到evert and revert具有不允许组合它们的类型。

  • 乍一看,这种情况与中描述的情况类似桑迪·马奎尔的这篇博文 https://reasonablypolymorphic.com/blog/existentials/,最终坚持unsafeCoerce以及。


以下是给予的看法Ev g a Representable实例可能会使问题更加明显。正如 dfeuer 所说 https://stackoverflow.com/a/56828434/2751851,这实际上是不可能的;不出所料,我不得不使用unsafeCoerce again:

-- Cf. dfeuer's answer.
newtype Goop g = Goop { unGoop :: forall y. g y -> y }

instance Representable (Ev g) where
    type Rep (Ev g) = Goop g
    tabulate f = Ev $ \e -> f (Goop (goopify e))
        where
        goopify :: (g Any -> Any) -> g x -> x
        goopify = unsafeCoerce
    index (Ev s) = \(Goop e) -> s e

While goopify当然看起来很令人担忧,我认为这里有可能是安全的。存在主义编码意味着任何e传递给包装函数的必然是元素类型上的多态提取器,它专门用于Any只是因为我要求这样的事情发生。既然如此,forall x. g x -> x是一个明智的类型e。这种舞蹈专门针对Any只是为了立即撤消它unsafeCoerce之所以需要,是因为 GHC 迫使我通过做出选择来摆脱存在主义。如果我省略了,就会发生这种情况unsafeCoerce在这种情况下:

Flap4.hs:64:37: error:
    • Couldn't match type ‘y’ with ‘x0’
      ‘y’ is a rigid type variable bound by
        a type expected by the context:
          forall y. g y -> y
        at Flap4.hs:64:32-37
      Expected type: g y -> y
        Actual type: g x0 -> x0
    • In the first argument of ‘Goop’, namely ‘e’
      In the first argument of ‘f’, namely ‘(Goop e)’
      In the expression: f (Goop e)
    • Relevant bindings include
        e :: g x0 -> x0 (bound at Flap4.hs:64:24)
   |
64 |     tabulate f = Ev $ \e -> f (Goop e) 
   |                                     ^
Failed, no modules loaded.

Prolegomena 需要在这里运行代码:

{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeFamilies #-}

import Data.Distributive
import Data.Functor.Rep
import Unsafe.Coerce
import GHC.Exts (Any)

-- A tangible distributive, for the sake of testing.
data Duo a = Duo { fstDuo :: a, sndDuo :: a }
    deriving (Show, Eq, Ord, Functor)

instance Distributive Duo where
    distribute u = Duo (fstDuo <$> u) (sndDuo <$> u)

Every Distributive可以制作函子Representable,尽管我们无法在 Haskell 中证明这一点(我想这不是建设性的)。但解决问题的一种方法是转班级。

newtype Evv f a = Evv
  {unEvv :: forall g. Representable g
         => (forall x. f x -> g x) -> g a}

instance Functor (Evv g) where
  fmap f (Evv q) = Evv $ \g -> fmap f (q g)

evert :: g a -> Evv g a
evert ga = Evv $ \f -> f ga

revert :: Representable g => Evv g a -> g a
revert (Evv f) = f id

newtype Goop f = Goop
  {unGoop :: forall x. f x -> x}

instance Distributive (Evv g) where
  collect = collectRep

instance Representable (Evv g) where
  type Rep (Evv g) = Goop g
  tabulate f = Evv $ \g -> fmap (\rg -> f (Goop $ \fx -> index (g fx) rg)) $ tabulate id
  index (Evv g) (Goop z) = runIdentity $ g (Identity . z)

我还没有尝试过这个Distributive直接(正如 HTNW 所建议的那样),但如果由于某种原因这是不可能的,我也不会感到惊讶。

警告:我还没有证明这实际上是免费的Representable!

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

在没有 unsafeCoerce 的情况下兼顾存在主义 的相关文章

  • Haskell:Where 与 Let

    我是 Haskell 的新手 我很困惑Where vs Let 它们似乎都提供了相似的目的 我读过一些比较Where vs Let但我很难辨别何时使用它们 有人可以提供一些背景信息或者一些示例来说明何时使用其中一种而不是另一种吗 哪里与让
  • 是否可以列出派生 Generic 的记录数据类型中字段的名称和类型?

    我知道对于派生 Data Data 的数据类型 constrFields http hackage haskell org package base 4 7 0 2 docs Data Data html v constrFields给出字
  • 使用通用元组函数一次进行多次折叠

    如何编写一个接受类型函数元组的函数ai gt b gt ai并返回一个函数 该函数接受类型元素的元组ai 类型的一个元素b 并将每个元素组合成一个新的元组ai 那是签名应该是这样的 f a1 gt b gt a1 a2 gt b gt a2
  • 用parsec解析递归数据

    import Data Attoparsec Text Lazy import Data Text Lazy Internal Text import Data Text Lazy pack data List a Nil Cons a L
  • 通过 Emacs 评估 ghci 或 Hugs 中的缓冲区

    在 Emacs 中使用 sml mode 我已经能够使用以下命令将缓冲区内容直接发送到较差的 SML 进程C c C b 现在我只想用 Haskell 做同样的事情 Haskell 模式似乎不支持这一点 所以我想知道 使用 Emacs 和
  • 如何在 Yesod 中使用 CSS 框架?

    我想将 Blueprint CSS 框架与 Yesod 一起使用 有没有最佳实践 因为 Yesod 使用 CSS 模板 所以在我看来我不能直接使用 css 文件 我必须将它们重命名为 lucius files 吗 如何将 CSS 添加到 d
  • 访问函数中的环境

    In main我可以读取我的配置文件 并将其提供为runReader somefunc myEnv正好 但somefunc不需要访问myEnv读者提供 链中的下一对也没有提供 需要 myEnv 中某些内容的函数是一个微小的叶函数 如何在不将
  • 导入 Haskell 模块

    我是哈斯克尔的新手 为什么当我尝试使用时Days from Data Time我收到此错误 Could not find module Data Time It is a member of the hidden package time
  • 如何为强制长度为 2^n 的向量类型定义可用的 Applicative 实例

    对于某些应用程序 我需要长度为 2 n 的向量 为了强制某些操作的长度匹配 我使用 ist 应用实例定义了我的类型 如下所示 LANGUAGE GADTs DataKinds FlexibleInstances FlexibleContex
  • 如何从 haskell 中的 IOError 获取 errno?

    我在 haskell 平台上 GHC 6 12 1 作为 apt get 安装在 Debian Squeeze 上 鉴于我需要在与最初引发它的线程不同的线程上使用它 如何从 IOError 中获取底层 errno 我需要这个的原因是因为我正
  • Haskell 类型系统的细微差别

    我一直在深入了解 haskell 类型系统的本质 并试图了解类型类的要点 我已经学到了很多东西 但我在下面的代码片段上遇到了困难 使用这些类和实例定义 class Show a gt C a where f Int gt a instanc
  • 我应该在 Turtle 或 Foldl 包中使用折叠吗?

    我在使用 Turtle 时遇到了一些困难 直到盯着难以理解的错误消息几分钟后才意识到我使用了错误的fold功能 https hackage haskell org package turtle 1 5 8 docs Turtle Shell
  • 将 num 的签名键入 double?

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

    对于以下 Haskell 表达式 返回 a gt gt f 应该读作 返回a gt gt f or 返回 a gt gt f 这里的相关规则是什么 规则始终是函数应用程序的优先级高于任何运算符 因此 return a gt gt f 被解析
  • 在 Yesod 生态系统中,对某些文本进行 urlencode 的最佳方式是什么?

    我想对一些文本进行 url 编码 例如 用 20 替换每个空格等 我找到了 HTTP Network HTTP Base urlEncode 并且可以使用它 但我想知道是否还有其他通常在 Yesod 生态系统中使用的东西 不幸的是 由于 U
  • 标准的能力

    我发现了一些使用标准的旧例子here http www serpentine com blog 2009 09 29 criterion a new benchmarking library for haskell 看起来好像早在 2009
  • 如何在 Haskell 中制作打勾游戏的图案?

    实现有 2 个参数的函数 ticktick 第一个参数是自然数元组 定义游戏场地的行数和列数 第二个列表包含由玩家 x 和玩家 o 轮流玩的坐标给出的井字游戏比赛的记录 打印游戏的实际状态 其中游戏区域将由字符 和 界定 空方块 以及字符
  • Haskell 中的尾递归字符串分割

    我正在考虑分割字符串的问题s在一个字符处c 这表示为 break c s 其中 Haskell 库定义break c 足够接近 br br s h t if c h then s else let h t br t in h h t 假设我
  • 简单 Haskell Monad - 随机数

    我正在尝试扩展代码这个帖子 https stackoverflow com questions 3944170 haskell and state 接受的答案 允许我能够基于以种子作为参数的函数 randomGen 调用 randomGen
  • Haskell:Data.Numbers.Primes 库在哪里?

    我尝试导入 Data Numbers Primes import Data Numbers Primes 伦哈斯克尔给了我 5 hs 1 8 Could not find module Data Numbers Primes Use v t

随机推荐

  • 在 SBT 中显示调试模式的时间戳?

    我的sbt更新很慢 我想看看详细情况 所以我有 sbt debug update gt sbtupdate log 问题是日志没有每一行的时间戳 如何启用它 据我所知 仅使用 SBT 选项是不可能的 然而这question https st
  • 在 Mac OS Catalina (10.15.7) 上安装 greenlet

    我想在我的 Mac OS Catalina 10 15 7 上运行基于 Python 的项目的本地副本 项目使用诗歌作为 Python 依赖项管理工具 在安装 python 依赖项时 它会在遵守 Greenlet 包时崩溃 我听说此类问题可
  • django admin list_filter“或”条件

    抱歉 如果这个问题之前已经被回答过 但我做了很多谷歌搜索但没有成功 我知道如何创建自定义list filter管理视图中的 s 例如子类化SimpleFilter 我真正想要的是一种方法 在管理列表视图上 检查 将它们组合在 OR 公式中的
  • 关闭 popoverview 后恢复第一响应者

    我在主视图控制器上有一个文本视图 我在视图控制器的导航栏上有一个栏按钮项目 当应用程序启动时 我执行以下操作 点击文本视图开始编辑并显示键盘 点击栏按钮以显示弹出视图 在不关闭弹出窗口视图的情况下 我关闭了键盘 通过点击屏幕上的任何其他视图
  • 更改 Windows.Ribbon 背景颜色

    我正在与System Windows Ribbon在我的项目中 我还使用其他一些库 例如AvalonDocking 我想做的是在应用程序中创建自己的主题 以便用户可以选择喜欢的主题 问题是我不明白RibbonTab更改为正确的颜色 当我更改
  • libdmtx 死了吗,建议替换吗?

    我一直在使用libdmtx http www libdmtx org在一个项目中并希望更新到较新的版本 但该项目似乎已经一年多没有更新了 最后一次更新 版本是 2011 年 6 月 Git 存储库 http libdmtx git sour
  • Safari 中的文本阴影被切断/不渲染超出元素边框

    正如标题所说 我有一个文本阴影 其中包含以下内容 body background white h1 color black text shadow 100px 100px 10px black In the Safari browser t
  • Selenium Python:没有这样的文件或目录:“/usr/local/bin/chromedriver”,但它存在并添加到路径中

    尝试在 Docker Apline Linux 上运行 selenium python 并收到 消息 chromedriver 可执行文件需要位于 PATH 中 错误 因为它认为该文件不存在 但在其他答案中尝试了我能做的一切 但它仍然无法启
  • 在 forEach 中调用类函数:Javascript 如何处理“this”关键字

    我是 Javascript 新手 只是想确保我理解它如何处理this关键字 因为 嗯 看起来很混乱 我已经在 StackOverflow 上查看了类似的问题 并想确保我没有继续错误的想法 所以我定义一个像这样的类 并且想要处理构造函数中收到
  • 在 Google App Engine 中接收邮件

    我正在阅读有关的教程接收邮件 http code google com appengine docs python mail receivingmail html 我按照指示更新了 app yaml 文件 application hello
  • 在单个 Java 项目中运行测试突然开始无提示地失败

    我有一个项目 我已经工作了几周 没有出现任何问题 自从昨天早上开始工作以来 我根本没有进行任何更改 但是从昨天下午开始 在该项目中运行任何测试都会默默失败 I see or rather don t see the same thing r
  • 使用ajax请求显示进度条进度

    我想在 ajax 请求触发和完成时使用 jquery ui 进度条显示进度 问题是我不知道如何根据ajax请求的进度设置进度条的值 下面是一段代码 function ajaxnews newstabs a click function e
  • 在 AngularJS 的 ng-bind 中使用过滤器后添加更多文本

    所以我想在 ng bind 指令中通过过滤器放置一个变量 ng bind input filter 但我想插入更多文字 ng bind input filter more 但这不起作用 有没有办法在 ng bind 中添加更多文本 就像您简
  • CMake子目录依赖

    我对 CMake 很陌生 事实上 我正在通过 Kdevelop4 widh C 进行尝试 我习惯为我创建的每个命名空间创建子目录 即使所有源代码都必须编译并链接到单个可执行文件中 好吧 当我在 kdevelop 下创建一个目录时 它会使用
  • Chart.js - 如何禁用悬停时的所有内容

    如何设置代码使图表上没有悬停效果 悬停选项 悬停 链接等 我正在使用 Chart js 下面是我的代码 我在其中设置饼图 Html div style width 90 div
  • 锁定安卓手机

    当用户按下按钮时 我试图以编程方式锁定设备 我知道我需要使用deviceAdminReciever我已经这样做了 但是每当我运行它时我的应用程序就会崩溃 以下是我的清单
  • 为什么 IE8 使用 Facebook 的 React.js 时会出现脚本错误

    我正在使用 Facebook 反应 不确定是什么导致了这个错误 似乎是反应本身 我收到 IE8 脚本错误 React js 的第 10898 行对象不支持此属性或方法 我没有使用缩小版本 这是带注释的开发版本 还有人遇到 facebook
  • 如何获取受 SQLAlchemy 影响的行数?

    如何使用 sqlalchemy 获取更新语句影响的行数 我正在使用 mysql 和 python pyramid from sqlalchemy engine base import ResultProxy classmethod def
  • 在命名空间中包装 extern“C”库时出现问题

    我正在使用 C 中的 C 库 libgretl 它的一些函数与我的代码冲突 所以我想将它包装在命名空间中 如下所示 namespace libgretl extern C include
  • 在没有 unsafeCoerce 的情况下兼顾存在主义

    最近我一直在研究这种类型 我理解它是自由分配函子的编码 有关切线背景 请参阅这个答案 https stackoverflow com a 56822105 2751851 data Ev g a where Ev g x gt x gt a