OCaml是否具有通用map()/ reduce()函数?

时间:2023-01-10 18:23:09

In Python map() works on any data that follows the sequence protocol. It does The Right Thing^TM whether I feed it a string or a list or even a tuple.

在Python中,map()处理遵循序列协议的任何数据。无论我是用字符串还是列表甚至元组提供它,它都是正确的东西。

Can't I have my cake in OCaml too? Do I really have no other choice but to look at the collection type I'm using and find a corresponding List.map or an Array.map or a Buffer.map or a String.map? Some of these don't even exist! Is what I'm asking for unusual? I must be missing something.

我不能在OCaml吃蛋糕吗?除了查看我正在使用的集合类型并查找相应的List.map或Array.map或Buffer.map或String.map之外,我真的别无选择吗?其中一些甚至不存在!我要求的是不寻常的吗?我肯定错过了什么。

4 个解决方案

#1


18  

The closest you will get to this is the module Enum in OCaml Batteries Included (formerly of Extlib). Enum defines maps and folds over Enum.t; you just have to use a conversion to/from Enum.t for your datatype. The conversions can be fairly light-weight, because Enum.t is lazy.

你最接近的是包含OCaml电池的模块Enum(以前的Extlib)。枚举在Enum.t上定义地图和折叠;你只需要使用转换为/从Enum.t转换为您的数据类型。转换可能相当轻,因为Enum.t是懒惰的。

What you really want is Haskell-style type classes, like Foldable and Functor (which generalizes "maps"). The Haskell libraries define instances of Foldable and Functor for lists, arrays, and trees. Another relevant technique is the "Scrap Your Boilerplate" approach to generic programming. Since OCaml doesn't support type classes or higher-kinded polymorphism, I don't think you'd be able to express patterns like these in its type system.

你真正想要的是Haskell风格的类型,比如Foldable和Functor(它概括了“maps”)。 Haskell库为列表,数组和树定义了Foldable和Functor的实例。另一种相关技术是通用编程的“Scrap Your Boilerplate”方法。由于OCaml不支持类型类或更高级别的多态性,我认为你不能在它的类型系统中表达这样的模式。

#2


11  

There are two main solutions in OCaml:

OCaml有两个主要解决方案:

  1. Jacques Garrigue already implemented a syntactically-light but inefficient approach for many data structures several years ago. You just wrap the collections in objects that provide a map method. Then you can do collection#map to use the map function for any kind of collection. This is more general than your requirements because it allows different kinds of data structures to be substituted at run time. However, this is not very useful in practice so the approach was never widely adopted.

    几年前,Jacques Garrigue已经为许多数据结构实现了语法轻,但效率低的方法。您只需将集合包装在提供map方法的对象中。然后你可以做集合#map来使用map函数进行任何类型的集合。这比您的要求更通用,因为它允许在运行时替换不同类型的数据结构。然而,这在实践中并不是非常有用,因此该方法从未被广泛采用。

  2. A syntactically-heavier but efficient, robust and static solution is to use functors to parameterize your code over the data structure you are using. This makes it trivial to reuse your code with different data structures. See Markus Mottl's OCaml translations of Okasaki's book "Purely Functional Data Structures" for some great examples.

    语法较重但有效,强大且静态的解决方案是使用函子来对您正在使用的数据结构进行参数化。这使得使用不同的数据结构重用代码变得微不足道。有关一些很好的例子,请参阅Markus Mottl的Okasaki的书“Purely Functional Data Structures”的OCaml翻译。

If you aren't looking for that kind of power and just want brevity then, of course, you can just create a module alias with a shorter name (e.g. module S = String).

如果你不是在寻找那种力量而只是想要简洁,那么你当然可以创建一个名字较短的模块别名(例如模块S = String)。

#3


1  

The problem is that each container has a different representation and requires different code for map/reduce to iterate over it. This is why there are separate functions. Most languages provide some sort of general interface for containers (such as the sequence protocol you mentioned) so functions like map/reduce can be implemented abstractly, but this is not done for the types you mentioned.

问题是每个容器都有不同的表示形式,并且需要不同的map / reduce代码来迭代它。这就是为什么有单独的功能。大多数语言为容器提供某种通用接口(例如您提到的序列协议),因此map / reduce之类的函数可以抽象地实现,但是对于您提到的类型不会这样做。

#4


-3  

As long as you define a type t and val compare (: t->t->int) in your module, Map.Make will give you the map you want.

只要在模块中定义类型t和val compare(:t-> t-> int),Map.Make就会为您提供所需的地图。

#1


18  

The closest you will get to this is the module Enum in OCaml Batteries Included (formerly of Extlib). Enum defines maps and folds over Enum.t; you just have to use a conversion to/from Enum.t for your datatype. The conversions can be fairly light-weight, because Enum.t is lazy.

你最接近的是包含OCaml电池的模块Enum(以前的Extlib)。枚举在Enum.t上定义地图和折叠;你只需要使用转换为/从Enum.t转换为您的数据类型。转换可能相当轻,因为Enum.t是懒惰的。

What you really want is Haskell-style type classes, like Foldable and Functor (which generalizes "maps"). The Haskell libraries define instances of Foldable and Functor for lists, arrays, and trees. Another relevant technique is the "Scrap Your Boilerplate" approach to generic programming. Since OCaml doesn't support type classes or higher-kinded polymorphism, I don't think you'd be able to express patterns like these in its type system.

你真正想要的是Haskell风格的类型,比如Foldable和Functor(它概括了“maps”)。 Haskell库为列表,数组和树定义了Foldable和Functor的实例。另一种相关技术是通用编程的“Scrap Your Boilerplate”方法。由于OCaml不支持类型类或更高级别的多态性,我认为你不能在它的类型系统中表达这样的模式。

#2


11  

There are two main solutions in OCaml:

OCaml有两个主要解决方案:

  1. Jacques Garrigue already implemented a syntactically-light but inefficient approach for many data structures several years ago. You just wrap the collections in objects that provide a map method. Then you can do collection#map to use the map function for any kind of collection. This is more general than your requirements because it allows different kinds of data structures to be substituted at run time. However, this is not very useful in practice so the approach was never widely adopted.

    几年前,Jacques Garrigue已经为许多数据结构实现了语法轻,但效率低的方法。您只需将集合包装在提供map方法的对象中。然后你可以做集合#map来使用map函数进行任何类型的集合。这比您的要求更通用,因为它允许在运行时替换不同类型的数据结构。然而,这在实践中并不是非常有用,因此该方法从未被广泛采用。

  2. A syntactically-heavier but efficient, robust and static solution is to use functors to parameterize your code over the data structure you are using. This makes it trivial to reuse your code with different data structures. See Markus Mottl's OCaml translations of Okasaki's book "Purely Functional Data Structures" for some great examples.

    语法较重但有效,强大且静态的解决方案是使用函子来对您正在使用的数据结构进行参数化。这使得使用不同的数据结构重用代码变得微不足道。有关一些很好的例子,请参阅Markus Mottl的Okasaki的书“Purely Functional Data Structures”的OCaml翻译。

If you aren't looking for that kind of power and just want brevity then, of course, you can just create a module alias with a shorter name (e.g. module S = String).

如果你不是在寻找那种力量而只是想要简洁,那么你当然可以创建一个名字较短的模块别名(例如模块S = String)。

#3


1  

The problem is that each container has a different representation and requires different code for map/reduce to iterate over it. This is why there are separate functions. Most languages provide some sort of general interface for containers (such as the sequence protocol you mentioned) so functions like map/reduce can be implemented abstractly, but this is not done for the types you mentioned.

问题是每个容器都有不同的表示形式,并且需要不同的map / reduce代码来迭代它。这就是为什么有单独的功能。大多数语言为容器提供某种通用接口(例如您提到的序列协议),因此map / reduce之类的函数可以抽象地实现,但是对于您提到的类型不会这样做。

#4


-3  

As long as you define a type t and val compare (: t->t->int) in your module, Map.Make will give you the map you want.

只要在模块中定义类型t和val compare(:t-> t-> int),Map.Make就会为您提供所需的地图。