使用透镜实现 3 种及以上类型之间的同构

2024-03-06

灵感来自关于ADT之间的多态函数的一个问题 https://stackoverflow.com/q/25192250/596361我试图在多个(不仅仅是 2 个)类型之间创建同构,这样每次我需要同构但不相同的类型时,我都可以在代码中添加一些convert.

假设我有 3 个 ADT:

data AB = A | B deriving (Show)
data CD = C | D deriving (Show)
data EF = E | F deriving (Show)

Using lens http://hackage.haskell.org/package/lens我可以在AB和CD、CD和EF之间实现2个同构:

{-# LANGUAGE MultiParamTypeClasses #-}
class Isomorphic a b where
  convert :: Iso' a b

instance Isomorphic AB CD where
  convert = iso ab2cd cd2ab
    where ab2cd A = C
          ab2cd B = D
          cd2ab C = A
          cd2ab D = B

instance Isomorphic AB EF where
  convert = iso ab2ef ef2ab
    where ab2ef A = E
          ab2ef B = F
          ef2ab E = A
          ef2ab F = B

转换A to E简单:A^.convert :: EF。转换D to B也很容易:D^.from convert :: AB。但如果我想从C to E via A,我必须为每个中间转换注释类型:

(C^.from convert :: AB)^.convert :: EF

我明白为什么编译器无法推断中间类型。可能存在多种同构,通过这些同构我们可以得到C to E。但是我可以简化我的代码,这样我就不用到处手动注释类型了吗?

我可以编写另一个实例来直接在之间进行转换CD and EF,但是如果我有超过 3 种类型怎么办?如果我有 5 个同构类型,则必须指定 10 个实例,因为同构对象之间的同构数量是完整图中的边数,这是一个三角数 http://oeis.org/A000217。我宁愿指定n-1实例,权衡是我写更多convert or from convert.

是否有一种惯用的方法可以使用以下方法在多种类型之间建立同构Iso http://hackage.haskell.org/package/lens/docs/Control-Lens-Iso.html from lens这样样板数量最少,而且我不必对所有内容进行类型注释?如果我必须使用 TemplateHaskell 来实现这一点,我该怎么做?

动机是,在我的作品中,我有许多极其复杂但愚蠢的类型,其中() -> (() -> ()) -> X and ((), X)同构于X。我必须手动包装和展开所有内容,并且我想要一些多态方法来将复杂类型减少为更简单的同构类型。


您可以将同构构建为星形图:具有所有其他连接到的规范“中心”类型。缺点是您必须在每个实例中显式指定集线器,并且您只能在共享集线器的类型之间进行转换。但是,您的两个要求(良好的类型推断和线性实例数)将得到满足。这样做的方法如下:

{-# LANGUAGE TypeFamilies #-}
import Control.Lens
import Unsafe.Coerce

data AB = A | B deriving (Show)
data CD = C | D deriving (Show)
data EF = E | F deriving (Show)

class Isomorphic a where
    type Hub a
    convert :: Iso' a (Hub a)

viaHub :: (Isomorphic a, Isomorphic b, Hub a ~ Hub b) => a -> b
viaHub x = x ^. convert . from convert

instance Isomorphic AB where
    type Hub AB = AB
    convert = id

instance Isomorphic CD where
    type Hub CD = AB
    convert = unsafeCoerce -- because I'm too lazy to do it right

instance Isomorphic EF where
    type Hub EF = AB
    convert = unsafeCoerce

In ghci:

> viaHub A :: EF
E
> viaHub A :: CD
C
> viaHub E :: AB
A
> viaHub E :: CD
C

以下是您如何将其用于示例:

class Unit a where unit :: a
instance Unit () where unit = ()
instance Unit b => Unit (a -> b) where unit _ = unit

instance Isomorphic X where
    type Hub X = X
    convert = id

instance (Unit a, Isomorphic b) => Isomorphic (a -> b) where
    type Hub (a -> b) = Hub b
    convert = iso ($unit) const . convert

instance Isomorphic a => Isomorphic ((), a) where
    type Hub ((), a) = Hub a
    convert = iso snd ((,)()) . convert

instance Isomorphic a => Isomorphic (a, ()) where
    type Hub (a, ()) = Hub a
    convert = iso fst (flip(,)()) . convert

现在你将拥有,例如

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

使用透镜实现 3 种及以上类型之间的同构 的相关文章

随机推荐

  • 地形条件资源

    我有以下内容 我想知道我做错了什么 因为我确信我不应该仅仅因为条件而将代码加倍 所以我想做 variable https value true resource aws security group http instance sg cou
  • 如何找到 numpy 矩阵中的最小值?

    嘿 这是一个快速而简单的问题 我如何找到这个矩阵的最小值 不包括 0 如 8 arr numpy array 0 56 20 44 68 0 56 8 32 56 0 44 68 20 56 0 当你使用numpy 你可以使用 arr ar
  • 使用可变宽度字体创建文本列

    我正在尝试为将在 MSN Messenger 上运行的 C 应用程序创建文本列 我很难让所有东西都排列整齐 这是我想要的输出的示例 1 Pizza Hut 123 Fake St 2 Domino s Pizza 123 Fake St 3
  • 运行时级别的 lambda 和方法引用有什么区别?

    我遇到过使用方法引用而不是 lambda 发生的问题 该代码如下 Comparator
  • HTML5 视频标签中的音频

    我注意到使用音频文件
  • 覆盖函数内部的全局变量不适用于 Spyder 4

    我尝试从函数内覆盖全局定义的数据框 不知何故 全局值不会改变 在函数内打印数据帧可以使用预期值 import pandas as pd rawData pd read csv music csv appTitles pd DataFrame
  • kubernetes 容器的响应丢失

    我已经在openstack上安装了kubernetes 该设置在 coreos 上有一个主节点和一个节点 我有一个在 UDP 端口 5060 上托管 SIP 应用程序的 pod 并且我已创建服务为NODEPORT在 5060 上 规格 sp
  • 如何在matlab中的imagesc图中添加图例

    我有以下代码 创建打印到文件的图形 f figure set gcf Visible off imagesc exp genes sorted cut h colorbar set gcf Colormap mycmap set gca x
  • Chrome 扩展选项卡 onUpdated 事件

    我正在构建一个 chrome 扩展 每次打开新选项卡并加载页面时都应该收到通知 为此我正在使用 chrome tabs onUpdated 事件 问题是 如果在某个域 具有 src 上托管的页面 选项卡上插入 iframe 则会触发 onU
  • 您可以在 Java EE Web 应用程序中实现 Vue.js 吗?

    我只是和我的同学一起开发一个工具 我们想使用 Vue js 作为 Web 界面 用于描述我们编程的内容 我们在 Eclipse 中开发了一个 Java EE Web 应用程序 我们使用 Tomcat 7 作为 Web 服务器 我搜索了很长时
  • Assert.Fail() 被认为是不好的做法吗?

    我在进行 TDD 时经常使用 Assert Fail 我通常一次进行一个测试 但是当我对稍后想要实现的事情有了想法时 我会快速编写一个空测试 其中测试方法的名称指示我想要以待办事项列表的形式实现的内容 为了确保我不会忘记 我在正文中放置了一
  • GWT maven编译器输出目录

    我需要使用 Maven 插件设置 GWT 编译器的输出目录位置 我研究了 GWT 编译器和 gwt maven plugin 文档 但没有找到任何选项 例如 我有两个名为editor and consolegwt maven plugin
  • javascript 使用 var 值作为新 var 的名称

    如何使用数组键 文本值 来引用同名变量 jsFiddle http jsfiddle net gBD4s var cr au gen bn fmt str var sbASCtrls cr ContentRating au Gold gen
  • 如何使用前向填充Python重新采样

    我的数据框 df3 看起来像这样 Id Timestamp Data Group Id 0 1 2018 01 01 00 00 05 523 125 5 101 1 2 2018 01 01 00 00 05 757 125 0 101
  • 为什么浏览器在 OSX 上渲染 rgba 的方式不同?

    我试图编写一些颜色操作代码 并在 alpha 上停留了很长一段时间 然后我 2 小时后 意识到浏览器以不同的方式渲染 rgba 我创建了这个测试 http jsbin com adekez 2 http jsbin com adekez 2
  • string_view 真的会引发释放后使用错误吗?

    根据一篇文章 here https alexgaynor net 2019 apr 21 modern c wont save us and there https github com isocpp CppCoreGuidelines i
  • 列“在选择列表中无效,因为它不包含在聚合函数或 GROUP BY 子句中”

    我想显示该列B在我的下面的 SQL 中 但是当我将其添加到查询中时 它给出了以下错误 T2 B 栏 在选择列表中无效 因为它不包含在 聚合函数或 GROUP BY 子句 My code SELECT A COUNT B as T1 B FR
  • 图的 k 顶点连通性

    是否有任何伪代码实现可以显示如何计算图的 k 顶点连通性 我无法在这里发布代码this http www cs sunysb edu algorith files edge vertex connectivity shtml本书因版权问题
  • 如何使用 API 3.1.1 在 Maven 插件中使用 Aether (eclipse)?

    我正在使用 API v3 1 1 开发一个新的 Maven 插件 因为我需要升级到 Maven 3 1 1 并且需要使用 Aether 方式处理工件存储库 以及检索工件版本的完整列表 我正在使用 Eclipse Aether 0 9 0 M
  • 使用透镜实现 3 种及以上类型之间的同构

    灵感来自关于ADT之间的多态函数的一个问题 https stackoverflow com q 25192250 596361我试图在多个 不仅仅是 2 个 类型之间创建同构 这样每次我需要同构但不相同的类型时 我都可以在代码中添加一些co