GADT 上的模式匹配失败

2024-02-01

我更多地使用 ReasonML 并发现了模式匹配type t从以下示例开始,无法处理该错误

错误:此模式与 t(float) 类型的值匹配,但需要一个与 t(int) 类型的值匹配的模式 float 类型与 int 类型不兼容

  type t('a) =
    | One: t(int)
    | Two: t(float);

  let x =
    fun
    | One => None
    | Two => None;

现在在某种程度上,如果这是关于函数的返回类型的话,这对我来说是有意义的。

我找到了答案(我认为)到一个同等的问题 https://stackoverflow.com/questions/10210269/pattern-matching-and-constructors。对于第二部分,答案似乎是忽略构造函数的绑定类型。 ReasonML 中也可能有同样的情况吗?

PS:请迂腐地纠正我的术语,我还在学习什么是什么。

P.p.s.:我知道我可以通过显式输入来解决最初的问题x但我真的很喜欢fun语法,因为它很有趣。


简短的回答是,GADT 使类型系统的表现力太强而无法完全推断。 例如,在您的情况下,以下函数都是全部的(也就是说,它们处理输入的所有可能值

let one = (One) => None
let two = (Two) => None

您可以通过在 OCaml 语法中添加显式反驳子句来检查它们是否完整(原因语法尚未更新以包括这些):

let one = function
| One -> None
| _ -> .

这里是点.意味着子句左侧描述的模式在语法上是有效的,但由于某些类型限制而不引用任何实际值。

因此,您需要告诉类型检查器您打算匹配类型的值t(a)对于任何a,这需要使用本地抽象类型来完成:

let x (type a, (x:t(a))) = switch(x){
| One => None
| Two => None
}

通过这个本地抽象注释,类型检查器知道它不应该替换这个变量a通过全局的具体类型(又名应该考虑局部a是一些未知的抽象类型),但它可以在匹配 GADT 时在本地对其进行细化。

严格来说,注释只需要在模式上,因此你可以写

let x (type a) = fun
| (One:t(a)) => None
| Two => None

请注意,对于具有 GADT 的递归函数,您可能需要使用完整的显式多态局部抽象类型表示法:

type t(_) =
| Int(int): t(int)
| Equal(t('a),t('a)):t(bool)

let rec eval: type any. t(any) => any = fun
| Int(n) => n
| Equal(x,y) => eval(x) = eval(y)

不同之处在于 eval 是递归多态的。看https://caml.inria.fr/pub/docs/manual-ocaml-4.09/polymorphism.html#sec60 https://caml.inria.fr/pub/docs/manual-ocaml-4.09/polymorphism.html#sec60 .

编辑:注释返回类型

避免可怕的“此类型将逃脱其范围”通常需要的另一个注释是在离开模式匹配时添加注释。 一个典型的例子是函数:

let zero (type a, (x:t(a)) = switch (x){
| One => 0
| Two => 0.
}

这里有一个歧义,因为在分支内部One,类型检查器知道int=a但是当离开这个上下文时,它需要选择等式的一侧或另一侧。 (在这种特定情况下,类型检查器将其留在自己的设备上决定(0: int)是更合乎逻辑的结论,因为0是一个整数,并且该类型与本地抽象类型没有任何联系a .)

可以通过在本地使用显式注释来避免这种歧义

let zero (type a, (x:t(a))) = switch (x){
| One => ( 0 : a )
| Two => ( 0. : a )
}

或者在整个函数上

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

GADT 上的模式匹配失败 的相关文章

随机推荐

  • Gstreamer 不会下沉到命名管道

    当 gst launch 管道的接收器是命名管道与普通文件时 我会得到不同的行为 我有一个 gst launch 管道 它在 OMAP 嵌入式 linux 板上显示来自摄像机的视频 并通过 Tee 以 avi 形式提供视频 gst laun
  • 如何在当前命名空间中获取Python交互式控制台?

    我想让我的 Python 代码在运行代码的过程中使用 code interact 之类的东西启动一个 Python 交互式控制台 REPL 但是 code interact 启动的控制台看不到当前命名空间中的变量 我该怎么做 mystrin
  • Python 中 case/switch 语句的等效项是什么? [复制]

    这个问题在这里已经有答案了 Python 是否有等效的switch陈述 Python 3 10 及以上版本 在 Python 3 10 中 他们引入了模式匹配 示例来自Python 文档 https docs python org 3 10
  • avro 类型的 createDataFrame 中的无限递归

    在此示例中 我从 createDataFrame 调用内部收到 StackOverflowError 它起源于涉及 java 类型推断的 scala 代码 该代码在无限循环中调用自身 final EventParser parser new
  • ggplot日期刻度向前移动一个月

    我确信这是一个简单的问题 但我无法从其他帖子中找到解决方案 如果我运行这个 test lt data frame dates as Date c 2016 10 31 2016 11 30 2016 12 31 2017 01 31 val
  • Maven忽略maven-frontend-plugin,没有错误

  • 构建无服务层的企业应用

    有很多教程教我们直接使用数据库来使用一些 ORM 但在现实生活中 我不记得有一个直接使用数据库而不是服务的大项目 所以这些教程的数量对我来说似乎很奇怪 直接连接的应用程序在数据库和应用程序之间的数据传输速度方面具有真正的优势 并且它们没有由
  • 多生产者多消费者多线程Java

    我正在尝试生产者 消费者问题的多个生产者 多个消费者用例 我使用 BlockingQueue 在多个生产者 消费者之间共享公共队列 下面是我的代码 Producer import java util concurrent BlockingQ
  • 构建GCC:bootstrap有哪些优点和缺点?

    我了解引导编译器构建的作用 但我不了解普通用户的优点和缺点 我认为对于 GCC 维护者来说是有价值的 配置GCC时 有两个选项 enable bootstrap and disable bootstrap 据我了解 对于普通编译器构建 en
  • SQL删除性能

    delete from a A where a ID 132 A表包含大约5000条记录 A ID是A表的主键 但是删除需要很长时间 有时它也会超时 该表包含三个索引 并由三个外键引用 谁能解释一下为什么即使我们是基于主键删除 它仍然需要很
  • 如何将所有请求修改为单个文件而不导致无限循环

    如何将所有请求发送到 www myurl com ANYTHING 并将它们全部发送到 www myurl com index php 我发现我可以通过以下方式发送所有内容 RewriteRule index php R Permanent
  • 无法在 Firefox 3.6 中的表格上获取最小高度

    我有一个问题 最小高度不适用于我绝对定位的桌子 但是 我可以使用高度在 IE 6 中工作 据我所知 IE 6 将高度视为最小高度 关于我如何让它发挥作用的任何线索 table cellspacing 0 style width 100 mi
  • Wii MotionPlus 支持

    我正在开发一个与Wiimote http en wikipedia org wiki Wii Remote 到目前为止我一直在使用维尤斯图书馆 http www wiiuse net 效果很好 然而 wiiuse 不支持运动加 http e
  • 定义 TypeScript 回调类型

    我在 TypeScript 中有以下类 class CallbackTest public myCallback public doWork void doing some work this myCallback calling call
  • 对象化关系:一对多,我可以有效地做到这一点吗?

    我对 Objectify 还很陌生 我有一个简单的问题 做某事的最好方法 假设我有一个允许人们发送和接收的应用程序 消息 为简单起见 请考虑电子邮件 当我的应用程序加载时 我没有 想要加载来自每个联系人的每条消息 向给定用户发送消息 那将是
  • 跨安装的 ios 唯一标识符

    我们需要唯一地标识该设备 并且它在安装 重新安装 时必须相同 到目前为止 我们一直在使用存储在钥匙串中的标识符 因此它在安装过程中仍然存在 现在 在 10 3 beta 版中 卸载应用程序时 钥匙串会自动删除 参考 https forums
  • Eclipse Neon CDT 运行配置未设置环境变量

    我刚刚从 Eclipse Kepler 升级到 Neon 3 发现除非在调试器下运行 否则在运行配置中设置环境变量不起作用 截至 2017 年 2 月 6 日 这被确定为 Neon 3 中的回归问题 但我一直无法找到解决方案 有其他人看到这
  • 在绘图文本过滤器中正确转义文本

    根据文件 应该用斜杠转义 但当我逃脱时 未添加文本 有错误消息说Stray near 但这是什么意思以及我该如何解决它 命令和输出 usr bin ffmpeg y i home www 255871 mov af aresample as
  • 为什么 Guava 中不推荐使用 Files.deleteDirectoryContents() ?

    在 Guava 10 中 Google 已弃用文件 deleteDirectoryContents https google github io guava releases 10 0 api docs com google common
  • GADT 上的模式匹配失败

    我更多地使用 ReasonML 并发现了模式匹配type t从以下示例开始 无法处理该错误 错误 此模式与 t float 类型的值匹配 但需要一个与 t int 类型的值匹配的模式 float 类型与 int 类型不兼容 type t a