purescript 中列表/数组中的类似记录类型

2023-12-23

有什么办法可以做类似的事情

first = {x:0}
second = {x:1,y:1}
both = [first, second]

这样both被推断为{x::Int | r}或类似的东西?

我尝试过一些事情:

[{x:3}] :: Array(forall r. {x::Int|r})    -- nope

test = Nil :: List(forall r. {x::Int|r})
{x:1} : test                              -- nope

type X r = {x::Int | r}
test = Nil :: List(X)              -- nope
test = Nil :: List(X())
{x:1} : test
{x:1, y:1} : test                  -- nope

我能想到的一切似乎都告诉我,不支持将这样的记录合并到集合中。有点像,函数可以是多态的,但列表不能。这是正确的解释吗?它让我想起了 F# 的“值限制”问题,尽管我认为这只是因为 CLR 限制,而 JS 不应该有这个问题。但也许是无关的。

有什么方法可以声明列表/数组来支持这一点吗?


您要找的是“存在类型 https://wiki.haskell.org/Existential_type”,而 PureScript 只是不支持像 Haskell 那样的语法级别的那些。但是你可以推出自己的:-)

一种方法要走是“数据抽象” - 即根据您想要对其执行的操作对数据进行编码。例如,假设您想要获取以下值x在某个时刻脱离他们。在这种情况下,创建一个数组:

type RecordRep = Unit -> Int

toRecordRep :: forall r. { x :: Int | r } -> RecordRep
toRecordRep {x} _ = x

-- Construct the array using `toRecordRep`
test :: Array RecordRep
test = [ toRecordRep {x:1}, toRecordRep {x:1, y:1} ]

-- Later use the operation
allTheXs :: Array Int
allTheXs = test <#> \r -> r unit

如果您有多个此类操作,您可以随时记录它们:

type RecordRep = 
    { getX :: Unit -> Int
    , show :: Unit -> String
    , toJavaScript :: Unit -> Foreign.Object
    }

toRecordRep r = 
    { getX: const r.x
    , show: const $ show r.x
    , toJavaScript: const $ unsafeCoerce r
    }

(注意Unit每个函数中的参数 - 它们是为了懒惰而存在的,假设每个操作都可能很昂贵)

但如果你真的需要类型机械,你可以做我所说的“穷人的存在主义类型”。如果仔细观察,存在类型只不过是“延迟”类型检查 - 延迟到您需要查看类型的程度。在 ML 语言中推迟某些事情的机制是什么?没错——一个函数! :-)

 newtype RecordRep = RecordRep (forall a. (forall r. {x::Int|r} -> a) -> a)

 toRecordRep :: forall r. {x::Int|r} -> RecordRep
 toRecordRep r = RecordRep \f -> f r

 test :: Array RecordRep
 test = [toRecordRep {x:1}, toRecordRep {x:1, y:1}]

 allTheXs = test <#> \(RecordRep r) -> r _.x

它的工作原理是这样的RecordRep包装一个函数,该函数接受另一个函数,该函数是多态的r- 也就是说,如果您正在查看RecordRep,你必须准备好给它一个可以与任何r. toRecordRep以使其精确类型在外部不可见的方式包装记录,但它将用于实例化您最终将提供的通用函数。在我的例子中这样的函数是_.x.

但请注意,这里存在问题:行r当您开始使用数组的元素时,它实际上是未知的,因此您无法对其执行任何操作。就像,完全一样。你所能做的就是得到x字段,因为它的存在是硬编码在签名中的,但除了x-你只是不知道。这是设计使然:如果你想把anything进入数组,你必须准备好得到anything出来了。

现在,如果您确实想对这些值执行某些操作,则必须通过约束来解释这一点r, 例如:

newtype RecordRep = RecordRep (forall a. (forall r. Show {x::Int|r} => {x::Int|r} -> a) -> a)

toRecordRep :: forall r. Show {x::Int|r} => {x::Int|r} -> RecordRep
toRecordRep r = RecordRep \f -> f r

test :: Array RecordRep
test = [toRecordRep {x:1}, toRecordRep {x:1, y:1}]

showAll = test <#> \(RecordRep r) -> r show

通过show像这样的函数是有效的,因为我们已经约束了行r以这样的方式Show {x::Int|r}必须存在,因此,应用show to {x::Int|r}必须工作。根据需要对您自己的类型类重复此操作。

这是有趣的部分:由于类型类是作为函数字典实现的,因此上面描述的两个选项实际上是等效的 - 在这两种情况下,您最终都会传递函数字典,只有在第一种情况下它是显式的,但在第二种情况下编译器会这样做为你。

顺便说一句,这也是 Haskell 语言支持的工作原理。

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

purescript 中列表/数组中的类似记录类型 的相关文章

随机推荐

  • 我可以在java中使用方法链接的抽象构建器类而不执行不安全操作吗?

    我试图为某些构建器类提供一个抽象基类 以便我可以轻松地在构建器实现之间重用代码 我希望我的构建器支持方法链接 因此方法必须返回最具体类型的 this 实例 我想我可以用泛型来做到这一点 不幸的是 我无法在不使用不安全操作的情况下做到这一点
  • 生成器不是迭代器吗?

    我有一个生成器 一个产生东西的函数 但是当试图将它传递给gensim Word2Vec我收到以下错误 类型错误 您不能将生成器作为句子参数传递 尝试迭代器 生成器不是迭代器的一种吗 如果没有 我如何从中创建一个迭代器 查看库代码 它似乎只是
  • 范围为“class”的 Pytest 装置不适用于“setup_class”方法

    我目前正在使用pytest addoption运行我的 API 测试 因此测试应该针对用户在命令行上使用的环境运行 在我的测试文件中 我试图实例化UsersSupport只上一次课 就通过了env争论 我的代码 测试 py import p
  • NSMutableData 的 mutableBytes 和 bytes 方法之间的区别

    两者都返回相同的指针 我知道 bytes属于NSData 为什么NSMutableData介绍 mutableBytes 是否只是为了代码清晰 以便更明显地访问可变数据 使用哪一个真的很重要吗 NSMutableData mydata NS
  • 使用ExternalProject_Add将Opus包含在Android中

    这可能很简单 我有一个使用 NDK 的 Android 项目 我想包括opus https opus codec org downloads 本机代码中的源代码 我尝试使用 CMake 的ExternalProject Add 属性 但我的
  • ASP.Net WebForms 路由 多个目的地的单一路由

    我正在考虑为我计划创建的新网站设置数据库路由 我一直在查看以下有关使用数据库中的FriendlyUrls 的教程 http www asp net web forms tutorials aspnet 45 getting started
  • 在 C 扩展中释放全局 VM 锁而不使用其他函数

    我不明白为什么在 Ruby C API 中释放或获取 GVL 时需要另一个间接级别 Both rb thread call without gvl and rb thread call with gvl 需要一个只接受一个参数的函数 但情况
  • DataTable 内的 Markdown 正在其周围添加段落

    当 DashTable 中使用 markdown 时 需要额外增加一个 p 添加标签使单元格和实习生所有行变大 import dash from dash import dash table app dash Dash app layout
  • 在三星上,Compose AlertDialog 始终采用全宽

    在我的配备 One UI 5 0 和 Android 13 的三星 Galaxy S22 上 撰写 AlertDialog 始终占据全宽 在其他设备上它的工作方式与预期一致 Compose版本是1 3 1 您只需下载即可重现此内容 我怀疑这
  • 为什么我的 WPF 应用程序禁用了拖放功能(即使当 AllowDrop 为 true 时)?

    我的 WPF 应用程序禁止从 Windows 资源管理器中删除文件 并显示停止标志光标 我尝试在主窗口和包含的控件上将AllowDrop属性 UIElement祖先的属性 设置为true 但完全没有运气 没有触发拖放事件 有什么想法或建议来
  • 区分具有未知功能的产品 - sympy

    我尝试了各种搜索 但找不到一个好的谷歌字符串来得出正确的结果 我有以下形式的产品 y x f x 其中 f 是 x 的未知函数 我希望 sympy 对 y 相对于 x 进行微分 有谁知道我该怎么做 怎么样 gt gt gt x sympy
  • jQuery .trigger('click') 在间隔函数内?

    这是一个改写的问题here https stackoverflow com questions 5031019 stuck on weird jquery error 经过一些测试后 我隔离了问题 但没有解决它的线索 无需阅读上一个问题 这
  • 为什么线程过程应该是静态的或成员函数

    为什么线程过程应该是静态的或成员函数 有什么正当理由吗 非静态成员变量有一个隐式的this编译器内部传递的参数 You have ClassInQuestion void threadFunc int 并且编译器内部创建了一个函数 void
  • DataTable.Merge 和 DataTable.ImportRow 不会更改 RowState

    我在 ADO NET 2 0 合并 导入数据时遇到问题 我需要将数据从一个通用表更新 插入到另一个表 并且两个表都保持相同的架构 以下代码在本地运行良好 但不会对数据库进行更改 OleDbDataAdapter localDA loadLo
  • mailgun 传入邮件事件获取附件 url

    我有一个节点端点 它接收 json 格式的传入电子邮件 其中包含来自 mailgun 的所有附件 附件位于 json 数组中 xxx com 用于隐私 attachments url https sw api mailgun net v3
  • 导航架构组件 - 将参数数据传递到 startDestination

    我有一个活动 A 启动活动 B 并向其传递一些意图数据 活动 B 托管来自新导航架构组件的导航图 我想将该意图数据作为参数传递给 startDestination 片段 如何做到这一点 好的 感谢 Google 团队的 Ian Lake 我
  • 正确传输和保护 Web 应用程序的用户密码

    我正在为我的硕士项目开发一个网络应用程序 这是一个供教授管理学生项目的系统 它使用Java作为服务器端代码 使用HSQLDB作为数据库 使用JSP作为表示层 并且运行在tomcat上 将存储的数据不包括任何敏感信息 学生 ID 财务信息等
  • FixIO 是做什么的?

    The System IO 文档 https hackage haskell org package base 4 5 0 0 docs System IO html包含一个神秘的 未记录的函数fixIO 它的来源 https hackag
  • 显示 Maven dependency:tree 中省略的版本?

    在 Eclipse 中 当我转到 Maven 依赖关系层次结构页面时 我得到的输出指出了哪些冲突导致版本被忽略 但是 如果我使用依赖 树 http maven apache org plugins maven dependency plug
  • purescript 中列表/数组中的类似记录类型

    有什么办法可以做类似的事情 first x 0 second x 1 y 1 both first second 这样both被推断为 x Int r 或类似的东西 我尝试过一些事情 x 3 Array forall r x Int r n