使用透镜实现 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 种及以上类型之间的同构 的相关文章

  • 导入 Haskell 模块

    我是哈斯克尔的新手 为什么当我尝试使用时Days from Data Time我收到此错误 Could not find module Data Time It is a member of the hidden package time
  • Haskell 中的前提条件检查有哪些选项

    这是一个简单的问题 我认为答案很复杂 一个非常常见的编程问题是函数返回某些内容 或者前置条件检查失败 在Java中 我会使用一些抛出异常的断言函数IllegalArgumentException在方法的开头 如下所示 method body
  • 如何为强制长度为 2^n 的向量类型定义可用的 Applicative 实例

    对于某些应用程序 我需要长度为 2 n 的向量 为了强制某些操作的长度匹配 我使用 ist 应用实例定义了我的类型 如下所示 LANGUAGE GADTs DataKinds FlexibleInstances FlexibleContex
  • 如何让 Show 显示函数名称?

    作为一个让我熟悉 Haskell 的简单练习 在 Youtube 上闲逛并偶然进入美国倒计时游戏节目之后 我想为数字游戏制作一个求解器 你得到 6 个数字 需要将它们与 为了得到给定的结果 到目前为止我所得到的是非常脑死亡的 let ope
  • 为什么 Haskell 的默认字符串实现是一个字符链接列表?

    Haskell 默认值的事实String众所周知 实现在速度和内存方面都效率不高 据我所知 lists一般来说 在 Haskell 中实现为单链表 并且适用于大多数小型 简单数据类型 例如Int 这似乎不是一个好主意 但是对于String这
  • 我应该在 Turtle 或 Foldl 包中使用折叠吗?

    我在使用 Turtle 时遇到了一些困难 直到盯着难以理解的错误消息几分钟后才意识到我使用了错误的fold功能 https hackage haskell org package turtle 1 5 8 docs Turtle Shell
  • Haskell 中的 print 是纯函数吗?

    Is print在 Haskell 中是纯函数 为什么或者为什么不 我认为不是 因为它并不总是返回与纯函数应返回的值相同的值 类型的值IO Int并不是真正的Int 它更像是一张纸 上面写着 嘿 Haskell 运行时 请生成一个Int如此
  • 如何在 Haskell 中向右或向左移动列表的 1 个元素?

    嗨 我一直在寻找答案 但找不到 假设我们有一个像这样的列表 1 10 4 5 3 我怎样才能将 5 向左移动 使这个列表变成 1 10 5 4 3 我尝试过了swapElementsAt通过找到该元素的索引 但它看起来非常不足 swapEl
  • Haskell 中的分类结构

    Hask通常被认为是一个范畴 其对象是类型 态射是函数 然而 我看到 Conor McBride pigworker 警告不要使用Hask多次 1 https stackoverflow com a 45905082 474311 2 ht
  • Haskell 中的中缀运算符优先级

    对于以下 Haskell 表达式 返回 a gt gt f 应该读作 返回a gt gt f or 返回 a gt gt f 这里的相关规则是什么 规则始终是函数应用程序的优先级高于任何运算符 因此 return a gt gt f 被解析
  • Java 中如何将 char 转换为 int? [复制]

    这个问题在这里已经有答案了 我是Java编程新手 我有例如 char x 9 我需要得到撇号中的数字 即数字 9 本身 我尝试执行以下操作 char x 9 int y int x 但没有成功 那么我应该怎么做才能得到撇号中的数字呢 ASC
  • Haskell 入门

    这个问题的答案是社区努力 help privileges edit community wiki 编辑现有答案以改进这篇文章 目前不接受新的答案或互动 几天来 我一直试图理解 Haskell 中的函数式编程范例 我通过阅读教程和观看截屏视频
  • 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 假设我
  • 有没有更好的方法将 UTC 时间转换为大纪元时间?

    我想将文件的修改时间设置为从 exif 数据获取的时间 为了从 exif 获取时间 我发现 Graphics Exif getTag Exif gt String gt IO Maybe String 要设置文件修改时间 我发现 Syste
  • : 中缀运算符在 Haskell 中的作用是什么?

    我正在阅读Haskell 简要介绍 http www haskell org tutorial index html 这不是那么温和 并且它反复使用 操作符而不直接解释它的作用 那么 它到底有什么作用呢 是 前置 运算符 x xs 返回一个
  • 如何将 int[] 转换为 uint8[]

    所以 我需要你的帮助 我找不到关于该主题的任何内容 Golang 是一门刚刚诞生的语言 所以对于像我这样的新手来说很难快速找到答案 预先声明的 Goint类型大小是特定于实现的 32 位或 64 位 数字类型 http golang org
  • Haskell - lambda 表达式

    我试图了解什么是有用的以及如何在 Haskell 中实际使用 lambda 表达式 我不太明白使用 lambda 表达式相对于定义函数的约定方式有何优势 例如 我通常会执行以下操作 let add x y x y 我可以简单地打电话 add
  • 在 C# 中将位从 ulong 复制到 long

    所以看来 NET 性能计数器类型 http msdn microsoft com en us library system diagnostics performancecounter aspx有一个恼人的问题 它暴露了long对于计数器
  • 用于从字符串安全转换的辅助函数

    回到 VB6 我编写了一些函数 让我在编码时无需关心字符串的 null 和 数字的 null 和 0 等之间的区别 编码时 没有什么比添加特殊情况更能降低我的工作效率了用于处理可能导致一些不相关错误的数据的代码 9999 10000 如果我
  • 将 Powershell 输出转换为 Markdown 文件

    我有以下代码 xmlFile C Users kraer Desktop bom xml xml xml Get Content xmlFile xml bom components component ForEach Object fin

随机推荐

  • 地形条件资源

    我有以下内容 我想知道我做错了什么 因为我确信我不应该仅仅因为条件而将代码加倍 所以我想做 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