将“列表”转换为“集合”?
OCaml 真的没有从列表转换为集合的函数吗?
如果是这样的话,是否可以制作一个通用函数list_to_set
?我尝试制作一个多态集,但没有成功。
Is it really true that OCaml doesn't have a function which converts from a list to a set?
If that is the case, is it possible to make a generic function list_to_set
? I've tried to make a polymorphic set without luck.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
基本问题:列表可以包含任何类型的元素。集合(假设您指的是标准的 Set 模块相反,依赖元素比较操作来保持平衡树。如果您没有对
t
进行比较操作,则不能希望将t 列表
转换为集合。实际问题:标准库的
Set
模块是函子化的:它将表示元素类型及其比较操作的 module 作为输入,并生成 作为输出代表集合的模块。使用列表的简单参数多态性来实现这项工作有点运动。为此,最简单的方法是将 set_of_list 函数包装在函子中,以便它本身由比较函数参数化。
然后,您可以使用 String 模块,它提供了合适的
compare
函数。还可以使用非函子化集的不同实现,例如电池和 Extlib 'PSet' 实现 (文档)。建议使用函子化设计,因为它具有更好的类型保证——您不能使用不同的比较操作来混合相同元素类型的集合。
注意:当然,如果您已经有一个给定的 set 模块,从 Set.Make 函子实例化,则不需要所有这些;但你的转换函数不会是多态的。例如,假设我在代码中定义了
StringSet
模块:然后我可以使用
StringSet.add
和StringSet 轻松编写
:stringset_of_list
.empty如果您不熟悉折叠,这里是一个直接的、非尾递归的递归版本:
Fundamental problem: Lists can contain elements of any types. Sets (assuming you mean the Set module of the standard library), in contrary, rely on a element comparison operation to remain balanced trees. You cannot hope to convert a
t list
to a set if you don't have a comparison operation ont
.Practical problem: the
Set
module of the standard library is functorized: it takes as input a module representing your element type and its comparison operation, and produces as output a module representing the set. Making this work with the simple parametric polymoprhism of lists is a bit sport.To do this, the easiest way is to wrap your set_of_list function in a functor, so that it is itself parametrized by a comparison function.
You can then use for example with the String module, which provides a suitable
compare
function.It is also possible to use different implementation of sets which are non-functorized, such as Batteries and Extlib 'PSet' implementation (documentation). The functorized design is advised because it has better typing guarantees -- you can't mix sets of the same element type using different comparison operations.
NB: of course, if you already have a given set module, instantiated form the Set.Make functor, you don't need all this; but you conversion function won't be polymorphic. For example assume I have the
StringSet
module defined in my code:Then I can write
stringset_of_list
easily, usingStringSet.add
andStringSet.empty
:In case you're not familiar with folds, here is a direct, non tail-recursive recursive version:
Ocaml 3.12 有扩展 (7,13 显式命名类型变量和7,14 一流模块)这使得实例化和传递多态值的模块成为可能。
在此示例中,
make_set
函数为给定的比较函数返回一个Set
模块,build_demo
函数根据给定的模块和列表构造一个集合值:但这并不能完全解决问题,因为编译器不允许返回值具有依赖于模块参数的类型:
可能的解决方法是返回操作的函数集合隐藏设定值:
Ocaml 3.12 has extensions (7,13 Explicit naming of type variables and 7,14 First-class modules) that make it possible to instantiate and pass around modules for polymorphic values.
In this example, the
make_set
function returns aSet
module for a given comparison function and thebuild_demo
function constructs a set given a module and a list of values:This doesn't fully solve the problem, though, because the compiler doesn't allow the return value to have a type that depends on the module argument:
A possible work-around is to return a collection of functions that operate on the hidden set value:
如果您不介意非常粗暴的方法,您可以使用多态哈希表接口。元素类型为unit的哈希表只是一个集合。
如果您只需要测试成员资格,这可能就足够了。如果您想要其他集合操作(例如并集和交集),这不是一个很好的解决方案。从打字的角度来看,它绝对不是很优雅。
If you don't mind a very crude approach, you can use the polymorphic hash table interface. A hash table with an element type of unit is just a set.
If you just need to test membership, this might be good enough. If you wanted other set operations (like union and intersection) this isn't a very nice solution. And it's definitely not very elegant from a typing standpoint.
只需扩展原始类型即可,如图
http://www.ffconsultancy.com/ocaml/benefits/modules.html
对于列表模块:
Just extend the original type, as shown in
http://www.ffconsultancy.com/ocaml/benefits/modules.html
for the List module:
使用核心库,您可以执行以下操作:
例如:
或者:
Using the core library you could do something like:
So for example:
Or: