在使用 Base 的 OCaml 中,如何构造一个包含“int * int”类型元素的集合?

2024-02-06

在 F# 中,我只需执行以下操作:

> let x = Set.empty;;
val x : Set<'a> when 'a : comparison

> Set.add (2,3) x;;
val it : Set<int * int> = set [(2, 3)]

我知道在 OCaml 中,当使用 Base 时,我必须提供一个具有比较函数的模块,例如,如果我的元素类型是string

let x = Set.empty (module String);;
val x : (string, String.comparator_witness) Set.t = <abstr>

Set.add x "foo";;
- : (string, String.comparator_witness) Set.t = <abstr>

但我不知道如何构造一个具有类型比较函数的模块int * int。我如何构建/获得这样的模块?


要创建有序数据结构,如 Map、Set 等,您必须提供一个比较器。在 Base 中,比较器是一个一流的模块(打包到值中的模块),它提供比较函数和见证该函数的类型索引。等等,什么?接下来,让我们首先定义一个比较器。如果您已经有一个具有类型的模块

 module type Comparator_parameter = sig 
     type t (* the carrier type *)

     (* the comparison function *)
     val compare : t -> t -> int 

     (* for introspection and debugging, use `sexp_of_opaque` if not needed *)
     val sexp_of_t : t -> Sexp.t
 end

那么你可以只提供给Base.Comparator.Make函子并构建比较器

 module Lexicographical_order = struct 
    include Pair
    include Base.Comparator.Make(Pair)
 end

哪里的Pair模块提供比较功能,

 module Pair = struct
   type t = int * int [@@deriving compare, sexp_of]
 end

现在,我们可以使用比较器来创建有序结构,例如,

 let empty = Set.empty (module Lexicographical_order)

如果您不想为订单创建单独的模块(例如,因为您无法为其提供一个好的名称),那么您可以使用匿名模块,如下所示

 let empty' = Set.empty (module struct
   include Pair
   include Base.Comparator.Make(Pair)
  end)

请注意,Pair模块,传递给Base.Comparator.Make函子必须绑定在全局范围内,否则类型检查器会抱怨。这都是关于这个见证价值的。那么这个见证人是关于什么的,它见证了什么。

任何有序数据结构(例如 Map 或 Set)的语义都取决于顺序函数。比较以不同顺序构建的两个集合是错误的,例如,如果您有两个由相同数字构建的集合,但一个按升序排列,另一个按降序排列,它们将被视为不同的集合。

理想情况下,类型检查器应该防止此类错误。为此,我们需要在集合的类型中对用于构建集合的顺序进行编码。这就是 Base 正在做的事情,让我们看看empty' type,

val empty' : (int * int, Comparator.Make(Pair).comparator_witness) Set.t

and the empty type

val empty : (Lexicographical_order.t, Lexicographical_order.comparator_witness) Set.t

令人惊讶的是,编译器能够看穿名称差异(因为模块具有结构类型)并理解Lexicographical_order.comparator_witness and Comparator.Make(Pair).comparator_witness见证了相同的订单,所以我们甚至可以比较empty and empty',

# Set.equal empty empty';;
- : bool = true

为了巩固您的知识,让我们以相反的顺序构建一组对,

module Reversed_lexicographical_order = struct
  include Pair
  include Base.Comparator.Make(Pair_reveresed_compare)
end

let empty_reveresed =
  Set.empty (module Reversed_lexicographical_order)

(* the same, but with the anonyumous comparator *)
let empty_reveresed' = Set.empty (module struct
    include Pair
    include Base.Comparator.Make(Pair_reveresed_compare)
  end)

和以前一样,我们可以比较反转集的不同变体,

# Set.equal empty_reversed empty_reveresed';;
- : bool = true

但是类型检查器禁止比较不同阶的集合,

# Set.equal empty empty_reveresed;;
Characters 16-31:
  Set.equal empty empty_reveresed;;
                  ^^^^^^^^^^^^^^^
Error: This expression has type
         (Reversed_lexicographical_order.t,
          Reversed_lexicographical_order.comparator_witness) Set.t
       but an expression was expected of type
         (Lexicographical_order.t, Lexicographical_order.comparator_witness) Set.t
       Type
         Reversed_lexicographical_order.comparator_witness =
           Comparator.Make(Pair_reveresed_compare).comparator_witness
       is not compatible with type
         Lexicographical_order.comparator_witness =
           Comparator.Make(Pair).comparator_witness 

这就是比较见证人的用途,它们可以防止非常严重的错误。是的,它比 F# 需要更多的输入,但完全值得,因为它提供了来自类型检查器的更多输入,现在能够检测真正的问题。

最后几点说明。 “比较器”这个词在 Janestreet 图书馆中是一个不断发展的概念,以前它曾经意味着不同的东西。接口也在变化,比如@glennsl提供的例子有点过时了,并且使用Comparable.Make模块而不是新的和更通用的Base.Comparator.Make.

此外,有时编译器在抽象类型时将无法看到比较器之间的相等性,在这种情况下,您需要在 mli 文件中提供共享约束。您可以采取Bitvec_o​​rder https://github.com/BinaryAnalysisPlatform/bap/blob/ad79508e53e28184305fa58d51c6440ce95f47f6/lib/bitvec_order/bitvec_order.mli以图书馆为例。它展示了如何使用比较器来定义相同数据结构的各种顺序以及如何使用共享约束。图书馆文档还解释了各种术语并给出了术语的历史。

最后,如果您想知道如何启用派生预处理器,那么

  1. 对于沙丘,添加(preprocess (pps ppx_jane))您的库/可执行规范的节
  2. 对于 ocamlbuild 添加-pkg ppx_jane option;
  3. 对于顶层(例如,ocaml or utop) use #require "ppx_jane";;(如果 require 不可用,则执行#use "topfind;;",然后重复)。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在使用 Base 的 OCaml 中,如何构造一个包含“int * int”类型元素的集合? 的相关文章

  • OCaml 作为 C 库,hello world 示例

    我希望通过 C 调用 OCaml 代码 方法是将 OCaml 编译为包含 C 接口的静态或共享库 这一页 https caml inria fr pub docs manual ocaml intfc html似乎解释了如何为 OCaml
  • 导入 python 模块的特殊性?

    我一直在使用 python 的 PySerial 库pyserial API http pyserial sourceforge net pyserial api html 我似乎无法理解为什么我必须专门导入模块的某个部分 这会给我一个错误
  • Node.js Async/Await 模块导出 [重复]

    这个问题在这里已经有答案了 我对模块创建有点陌生 想知道 module exports 并等待异步函数 例如 mongo connect 函数 完成并导出结果 在模块中使用 async await 正确定义了变量 但是当尝试通过要求模块来记
  • OCaml 中的不可变变量

    我正在学习 OCaml 我对变量的不变性有点困惑 根据我正在读的书 变量是不可变的 到目前为止一切顺利 但到底为什么我可以这样做 let foo 42 let foo 4242 我缺少什么 我认为最好的解释方法是举个例子 考虑以下代码 在
  • Magento:如何覆盖本地模块中的模型

    我试图在本地文件夹中覆盖本地文件夹中的模块 但我不知道是否可能 这就是我所做的 我创建了 local Mycompany Modulename Model Model php 我想覆盖 local Othercompany Modulena
  • 为什么将模块级代码放入函数中然后调用该函数在Python中速度更快?

    在亚历克斯 马尔泰利的回应中使 Python 脚本面向对象 https stackoverflow com questions 1813117 making a python script object oriented 他提到在 Pyth
  • VBA 架构技巧 - 宏封装

    我拼凑了 Excel 的概念证明 以从数据库获取数据 并需要将其打包 以便可以将其分发给我们的客户 我的第一次尝试只是将所有代码放入代码模块中 但随后在 Excel 中我可以看到宏列表中的所有模块 而我实际上只想要列表中的主要模块 我猜想我
  • 在需要时初始化模块

    我有一个模块 里面有一些初始化代码 加载模块时应执行 init 目前我正在这样做 in the module exports init function config do it in main var mod require myModu
  • 为什么在 OCaml 中更喜欢柯里化而不是元组参数?

    Caml简介 http www cs jhu edu scott pl lectures caml intro html says 请注意 在 Caml 中 最好对多参数函数使用柯里化函数定义 而不是元组 比较时 a gt b gt c调用
  • 为什么计算斐波那契数需要很长时间?

    几天前我开始学习Ocaml 我尝试编写一个斐波那契数字程序 let rec fib a if a 1 a 2 then 1 else fib a 1 fib a 2 该代码不是最佳的 因为我不知道如何处理异常情况 但现在 如果我尝试计算 f
  • 我们可以在 android studio 中拥有没有 app 文件夹的项目,并将所有内容(java/res/etc)放在根目录中吗

    我想知道在 Android studio 中是否可以有没有应用程序模块 应用程序或任何其他名称 的 android 项目 意味着我可以在项目本身的根目录中创建包和资源 而不是使用应用程序模块 编辑 结构看起来像 MyApp idea gra
  • python,从模块调用函数时遇到问题

    我导入了一个模块 如下所示 filename email mymodule import actions filename 我遇到的问题是 该文件是立即执行的 我宁愿从文件中执行特定的函数 这样我可以通过它发送变量 我基本上都是使用插件 所
  • 变体的结构比较

    我想处理整数行的限制 我想拥有Pervasives compare treat RightInfinity gt Point x对全部x 以及反函数LeftInfinity In the ocaml REPL type open pt Le
  • 如何在 Ocaml 中表示一个简单的有限状态机?

    我用 C 和 Java 编写过一些状态机 但从未用过像 Ocaml 这样的函数式语言 问题是我不知道我是否可以从对象语言版本中调整代码 因为在 Ocaml 中记录和变体比类更强大 所以 我需要一个事件驱动的有限状态机 像 UML 中的分层结
  • 模块路径格式错误...第一个路径元素中缺少点

    我有一个包含 2 个不同可执行文件的项目 每个可执行文件都有自己的依赖项以及对根的共享依赖项 如下所示 Root gt server gt main go gt someOtherFiles go gt go mod gt go sum g
  • 如何使用 python 模块的多个 git 分支?

    我想使用 git 来同时处理我正在编写的模块中的多个功能 我目前正在使用 SVN 只有一个工作区 因此我的 PYTHONPATH 上只有该工作区 我意识到这不太理想 所以我想知道是否有人可以建议一种更 正确 的方法来做到这一点 让我用一个假
  • 在 OCaml 中,这是什么类型定义:'a.单位 -> 'a

    问题 这是我第一次看到像这样的类型定义 a unit gt a in 记录中的显式多态类型 https stackoverflow com questions 23320990 explicit polymorphic type in re
  • 在 Rust 中使用父目录中的模块

    是否可以以这种方式构建 Rust 项目 目录结构 src a bin1 rs b bin2 rs common mod rs 来自 Cargo toml bin name bin1 path src a bin1 rs bin name b
  • 没有名为 pandas_datareader 的模块

    我刚刚安装了pandas datareader using pip install pandas datareader运行成功 现在我尝试将它用于教程 当我尝试导入时出现此错误 import pandas datareader as pdr
  • Pandas datetools模块错误

    我正在尝试从 pandas datetools 调用模块 但收到错误消息 指出 mofule 对象没有我所调用的名称的属性 想知道是否有人可以阐明这个问题 下面是我尝试使用的代码 import blpapi import pandas as

随机推荐

  • Bash 脚本 - 变量内容作为命令运行

    我有一个 Perl 脚本 它给我一个定义的随机数列表 这些随机数对应于文件的行 接下来我想使用从文件中提取这些行sed bin bash count cat last queries txt wc l var perl test pl te
  • 如何通过拖动顶部的 div 来调整其大小?

    我想在拖动两个 div 之间的部分时调整 div 的大小 在搜索中我发现this http jsfiddle net gaby Bek9L 1779 但我不知道如何使这个水平而不是可用的垂直拖动 我的 div 看起来像 div div di
  • Install4j:有没有办法用包含占位符的文本覆盖欢迎消息?

    我需要覆盖install4j欢迎消息 其中包含我需要在运行时解析的占位符文本 将从属性文件中读取替换值 welcomeLabel3 Text 0 another text 1 无法向系统消息添加占位符 您必须指定整个消息 但是 您可以使用安
  • 如何从 javascript 文件(而不是 vue 组件)获取 vuex 状态

    我正在使用 vuex 2 1 1 并让事情在 vue 单文件组件中工作 然而 为了避免 vue 单文件组件中出现太多问题 我将一些函数移至utils js我将其导入到 vue 文件中的模块 在这个utils js我想阅读 vuex 状态 我
  • 初学者:AVR C++ Atmel Studio 6

    我在确定我可以访问哪些库时遇到问题 我知道我可以使用 Atmel Studio 6 IDE 用 C 对微控制器 Atmega328p 进行编程 但是 我无法弄清楚我可以访问哪些库的记录在哪里 例如 我可以使用 STL 例如向量 双端队列 吗
  • Google Maps API V3 -> 利用 MarkerCluster 但簇本身是否特定于绘制的多边形/区域?

    好吧 让我以我已经创建了很多谷歌地图的事实作为这个问题的序言 但它们是严格的标记和表示路线的折线以及一些处理程序交互 现在我希望基本上显示一张世界地图 主要是北美 我想用我拥有的一些纬度 经度将这片大陆分成我预定义的区域 使用这些区域 我想
  • CSS 面包屑箭头指向左侧

    我发现这个 css 面包屑指向右侧 我想指向左侧 相信我 我一遍又一遍地尝试 但没有成功 请有人告诉我该怎么做 div span display inline block position relative background 88b7d
  • 改造 - 更改 BaseUrl

    我有一个场景 我必须使用相同的基本 URL 调用 API 例如www myAPI com但以不同的baseUrl 我有一个 Retrofit 2 的实例 它是通过Builder return new Retrofit Builder bas
  • 将 UL 在 DIV 内垂直居中

    我有以下内容 div style background Red height 100px ul li a href Home a li ul div 我想将 ul 垂直居中在 div 中 但我不知道如何 小提琴演示 http jsfiddl
  • 如何在C++03中用sprintf正确替换sprintf_s?

    sprintf s是该函数的 Microsoft 实现sprintf他们修补了一个缺陷 添加了一个参数来获取函数限制写入的边界值 等效的引入C 11 snprintf 但在这里 我们谈论的是C 03 syntax 签名 count char
  • 为什么 Unity 会忽略非静态公共字段的初始化值?

    我在用着InvokeRepeating http docs unity3d com ScriptReference MonoBehaviour InvokeRepeating html调用游戏中的方法 我打电话InvokeRepeating
  • 在Featuretools中计算多个训练窗口的特征

    我有一张包含客户和交易的表 有没有办法获取过去 3 6 9 12 个月过滤的功能 我想自动生成功能 过去 3 个月的跨性别者数量 过去 12 个月内跨性别者数量 过去 3 个月的平均跨性别者 过去 12 个月的平均跨性别者 我尝试过使用tr
  • Kafka重启时如何让Kafka Source重新连接

    我创建一个Source使用 Reactive Kafka 的消费者记录如下 val settings ConsumerSettings system keyDeserializer valueDeserializer withBootstr
  • MYSQL:转换时间戳 --> 时间

    我有这个 MYSQL 表 ID TIMESTAMP TIME 1 2010 05 29 01 17 35 1 2010 05 29 01 23 42 等等 现在我需要将 TIMESTAMP 值复制到 TIME 行中 新的 TIME 行是通过
  • Android + Google 一键刷新令牌?

    每当我使用 Android 应用程序登录时谷歌一键 我收到一个TOKEN ID有效期约为一个小时 我应该如何获得刷新令牌以避免在该 TOKEN 时每小时登录expires 我查了官方文档 但没有关于刷新令牌的内容 这是否意味着每次发生这种情
  • 如何修复在python中接收不到kafka消息但在shell中接收到相同消息的问题?

    我想消费来自 kafka 主题的消息 我正在使用 debezium 它记录 mongodb 更改并将它们放入 kafka 队列中 我可以使用 python 代码连接到 kafka 列出 kafka 主题 虽然 当我想使用消息时 它都是空白的
  • 如何从 Typescript 中的函数获取参数类型[重复]

    这个问题在这里已经有答案了 我可能错过了文档中的某些内容 但我无法在打字稿中找到任何方法来获取函数中参数的类型 也就是说 我有一个函数 function test a string b number console log a consol
  • ORACLE IIF 声明

    我在编写 IIF 语句 表和下面给出的语句时遇到错误 陈述 SELECT IIF EMP ID 1 True False from Employee Table CREATE TABLE SCOTT EMPLOYEE EMP ID INTE
  • 自动 jquery 样式表切换器

    我见过许多 css 切换器 它们放置一个按钮 允许用户更改样式以适合他们的口味 我正在寻找尚未找到的类似解决方案 这是最接近的 http net tutsplus com demos 03 jQueryStyleSwitcher demo
  • 在使用 Base 的 OCaml 中,如何构造一个包含“int * int”类型元素的集合?

    在 F 中 我只需执行以下操作 gt let x Set empty val x Set lt a gt when a comparison gt Set add 2 3 x val it Set