一起使用 makeLenses、类约束和类型同义词

2024-01-22

我对 Haskell 很陌生并且想使用makeLenses from Control.Lens类约束与类型同义词一起使我的函数类型更加紧凑(可读?)。

我试图提出一个最小的虚拟示例来演示我想要实现的目标,并且该示例除此之外没有其他目的。

如果您对上下文感兴趣,在这篇文章的末尾,我添加了一个更接近我原来问题的示例。

最小的例子

举个例子,假设我定义了以下数据类型:

data State a = State { _a :: a
                     } deriving Show     

,我还为此制作了镜头:

makeLenses ''State

为了对类型参数强制执行类约束a由类型构造函数使用State我使用智能构造函数:

mkState :: (Num a) =>  a -> State a
mkState n = State {_a = n}

接下来,假设我有许多具有与此类似的类型签名的函数:

doStuff :: Num a => State a -> State a
doStuff s = s & a %~ (*2)

这一切都按预期工作,例如:

test = doStuff . mkState $ 5.5 -- results in State {_a = 11.0}

Problem

我尝试使用以下类型同义词:

type S = (Num n) => State n -- Requires the RankNTypes extensions

, 和...一起:

{-# LANGUAGE RankNTypes #-}

,试图简化类型签名doStuff:

doStuff :: S -> S

,但这会出现以下错误:

Couldn't match type `State a0' with `forall n. Num n => State n'
    Expected type: a0 -> S
    Actual type: a0 -> State a0
In the second argument of `(.)', namely `mkState'
    In the expression: doStuff . mkState
    In the expression: doStuff . mkState $ 5.5
Failed, modules loaded: none.

Question

我目前对 Haskell 的了解不足以理解导致上述错误的原因。我希望有人可以解释导致错误的原因和/或建议其他方法来构造类型同义词或为什么这样的类型同义词是不可能的。

背景

我原来的问题看起来更接近这个:

data State r = State { _time :: Int
                     , _ready :: r
                     } deriving Show

makeLenses ''State

data Task = Task { ... }

在这里我想强制执行类型_ready是一个实例Queue使用以下智能构造函数的类:

mkState :: (Queue q) => Int -> q Task -> State (q Task)
mkState t q  = State { _time = t
                     , _ready = q
                     }

我还有许多具有与此类似的类型签名的函数:

updateState :: Queue q => State (q Task) -> Task -> State (q Task)
updateState s x = s & ready %~ (enqueue x) & time %~ (+1)

我想使用类型同义词S能够重写此类函数的类型:

updateState :: S -> Task -> S

,但与第一个最小示例一样,我不知道如何定义类型同义词S或者是否有可能。

也许尝试简化类型签名并没有真正的好处?

相关阅读

我已阅读以下相关问题:

  • 数据记录的类约束 https://stackoverflow.com/questions/11585891/class-constraints-for-data-records
  • 类型同义词与类型类约束是否可能? https://stackoverflow.com/questions/24232829/are-type-synonyms-with-typeclass-constraints-possible

这也可能是相关的,但鉴于我目前对 Haskell 的理解,我无法真正理解所有内容:

  • 将关联类型同义词与类约束统一起来 https://stackoverflow.com/questions/11493603/unifying-associated-type-synonyms-with-class-constraints

跟进

我已经有一段时间没有机会做一些 Haskell 了。感谢@bheklilr,我现在设法引入了一个类型同义词,只是为了遇到下一个我仍然无法理解的类型错误。我发布了以下后续问题类型同义词导致类型错误 https://stackoverflow.com/questions/31772516/type-synonym-causes-type-error关于新类型错误。


您会看到该错误,特别是因为.运营商和您的使用RankNTypes。如果你把它从

test = doStuff . mkState $ 5.5

to

test = doStuff $ mkState 5.5

or even

test = doStuff (mkState 5.5)

它会编译。为什么是这样?看类型:

doStuff :: forall n. Num n => State n -> State n
mkState :: Num n => n -> State n

(doStuff) . (mkState) <===> (forall n. Num n => State n -> State n) . (Num n => n -> State n)

希望括号有助于清楚地表明这一点,n from forall n. Num n ... for doStuff是一个不同类型的变量Num n => ... for mkState因为范围forall只延伸到括号末尾。因此,这些函数实际上无法组合,因为编译器将它们视为单独的类型!其实是有特殊规定的$专门用于使用的运算符STmonad 正是出于这个原因,所以你可以这样做runST $ do ....

您也许可以使用 GADT 更轻松地完成您想要的任务,但我不相信lens' TemplateHaskell将与 GADT 类型一起使用。然而,在这种情况下,您可以很容易地编写自己的代码,所以这没什么大不了的。


进一步解释:

doStuff . mkState $ 5.5

doStuff $ mkState 5.5

在第一个中,doStufffor all Num types n,其类型为State n -> State n, 然而mkState says for some Num type m,其类型为m -> State m。这两种类型并不相同,因为“对于所有人”和“对于某些”量化(因此ExistentialQuantification),因为编写它们对于某些人来说意味着Num m你可以生产所有Num n.

In the doStuff $ mkState 5.5,你相当于

(forall n. Num n => State n -> State n) $ (Num m => State m)

请注意,后面的类型$不是一个函数,因为mkState 5.5已全面应用。所以这有效是因为for all Num n你可以做State n -> State n,并且你正在为其提供一些Num m => State m。这很直观。同样,这里的区别在于组合与应用。您无法将适用于某些类型的函数与适用于所有类型的函数组合在一起,但您可以将值传递给适用于所有类型的函数(此处的“所有类型”表示forall n. Num n => n).

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

一起使用 makeLenses、类约束和类型同义词 的相关文章

随机推荐

  • 我的 docker 容器有多少个 CPU?

    我正在编写一个并行运行的库 该库经常在 docker 容器中使用 我想启动与我的 docker 容器分配的核心一样多的线程 docker 是否将 CPU 限制设置为环境变量 例如 如果我的用户在创建容器时设置了两个 CPU docker r
  • 使用 Scala 新动态类型的动态代理

    是否可以使用 Scala 新的动态类型功能创建类似 AOP 的拦截器 例如 是否可以创建一个通用的秒表拦截器 可以与任意类型混合来分析我的代码 或者我仍然需要使用 AspectJ 吗 我相当确定Dynamic仅当您选择的对象尚不具有您选择的
  • 在 Sencha Touch 中禁用轮播过度滚动/过度拖动

    在 Sencha Touch 2 轮播的末尾或开头 用户可以将项目拖过它应该能够到达的位置并显示白色背景 此处的屏幕截图 https i stack imgur com i10Ak png https i stack imgur com i
  • 在 python 3 中解析 .docx

    我目前正在编写一个 python 3 程序 该程序可以解析某些 docx 文件并从中提取文本和图像 我一直在尝试使用docx https github com mikemaccana python docx但它不会导入到我的程序中 我已经安
  • 在 Android 版 Phonegap 中调用 SOAP Web 服务

    我想打电话SOAP网络服务在Phonegap Android 我已经尝试过这段代码但是在回复文字有未定义和Status Error
  • JPA (Hibernate) 列映射中的原始类和包装类有什么区别?

    例如 数据库表中有一个整数列 然后在java模型中 它可以映射为原始整数 and Integer 我的问题是在这种情况下 int 和 Integer 有什么区别 以及性能问题 谢谢 我倾向于避免使用原语 对于 Id 属性尤其如此 这使得可以
  • LiquibasegenerateChangeLog 失败:Java 堆空间

    当我尝试从 DB2 数据库生成 SQL 数据时 遇到 Java 堆空间问题 大约有 25 个表 大约 1000 条记录 我使用以下脚本生成变更集数据 C liquibase 3 0 2 bin gt liquibase driver com
  • 多个超级用户命令 Android

    我正在尝试运行这个 String hin1 su c mount o remount rw t yaffs2 dev block mtdblk3 system try Runtime getRuntime exec hin1 catch I
  • 在数据表中启用滚动 X 时禁用底部搜索

    我正在尝试数据表中的数据显示https datatables net https datatables net i can show data from MYSQL to Datatables but i want column in da
  • Spring Boot 1.4、Spock 和 application.properties

    我正在尝试使用 Spock 为我的 Spring Boot 1 4 0 编写一些测试 但我的 application test properties 文件没有被拾取 我的 gradle 中有这个 dependencies compile o
  • 验证类 - 应该返回 false 还是抛出异常?

    我正在创建一个验证字符串的类 字符串无法通过的原因有很多 抛出异常或返回错误 错误代码更有意义吗 优点缺点 验证器不应抛出异常 因为验证器失败并不是 异常 事件 如果代码的其余部分收到错误数据 则应抛出异常 当您运行验证器函数时 您显然已准
  • 无法加载资源,插件在 iOS 上处理加载

    每次我尝试在服务器上查看视频文件时 我都会在 iOS 的 Safari Chrome 上收到此错误 我使用的是 blob 服务器 然后是 Apache 服务器 所以我不确定问题是什么 但是 当我只使用 Apache 时 我确实收到此错误 但
  • 在 iOS 中使用 pinterest 登录

    里面有关于pin的解释面向开发者的 Pinterest https developers pinterest com ios 但我仍然有以下两个问题 如何登录 用户登录后如何从服务器获取登录用户的响应 我已经浏览了谷歌和堆栈溢出上提供的所有
  • 将未知的十六进制数字转换为经度和纬度

    F3 c8 42 14 latitude 05 13637 should be nearby this coordinate 5d a4 40 b2 longitude 100 47629 should be nearby this coo
  • 在 Java 中从 Pentaho .prpt 报告文件生成 PDF - 依赖关系混淆

    谁能帮助我开始在 Maven 环境中使用 java 从 Pentaho prpt 文件生成 PDF 我有 Pentaho Reporting 3 5 for Java Developers 一书 我正在尝试其中的一个示例 本质上是 Reso
  • 在 R 中拟合平滑样条线(GAM 函数):拟合样条线所需的结数出现错误 - 结点要求增加

    我正在尝试将平滑样条拟合到看起来有两个峰值的数据 首先 我将平滑样条拟合到数据中 以识别结的潜在位置 library npreg library splines library mgcv x lt c 20 70 20 44 20 58 2
  • 将对象序列化为 XElement 并在内存中反序列化

    我想将对象序列化为 XML 但不想将其保存在磁盘上 我想将它保存在 XElement 变量中 用于与 LINQ 一起使用 然后反序列化回我的对象 我怎样才能做到这一点 您可以使用这两个扩展方法在 XElement 和对象之间进行序列化和反序
  • 如何检测与 puppeteer 一起使用的 chrome 版本?

    我读到 puppeteer 使用最新版本的 chrome 我在哪里可以找到它正在使用的版本 我不想访问窗口上的导航器对象来获取它 基本上没有什么运行时 只是想知道 puppeteer 作为一个包是否在某处列出了它的依赖项 基本上 我想从其他
  • 通过javascript动态添加css到页面

    我正在制作一个将添加到外部网站的小部件 并且我制作了一个页面 可以生成 css 供他们设置样式 文本颜色 背景颜色 字体大小等 我最终得到了一个充满 CSS 的文本区域 供他们复制 粘贴到他们的网站 有没有办法将此 css 添加到当前页面以
  • 一起使用 makeLenses、类约束和类型同义词

    我对 Haskell 很陌生并且想使用makeLenses from Control Lens类约束与类型同义词一起使我的函数类型更加紧凑 可读 我试图提出一个最小的虚拟示例来演示我想要实现的目标 并且该示例除此之外没有其他目的 如果您对上