Haskell 一个数据有两种结构:函数式编程与命令式编程

Haskell 一个数据有两种结构:函数式编程与命令式编程,haskell,data-structures,functional-programming,Haskell,Data Structures,Functional Programming,假设在C中,我们有以下结构: struct MyData { char key1[20]; long key2; ... /* some data */ }; 基本上,除了一些数据外,我们还有两个键:键1和键2。假设我们需要以两种不同的方式管理MyData的一组对象,例如,基于key1或key2(但不是两者)快速查找相应的对象。满足此要求的一种方法是分别根据这两个键构建两个不同的RB树(或哈希表)。在C/C++中,数据不需要复制,因为我们只需要记录对象的指针 在上面的

假设在C中,我们有以下结构:

struct MyData {
    char key1[20];
    long key2;
    ...  /* some data */
};
基本上,除了一些数据外,我们还有两个键:键1和键2。假设我们需要以两种不同的方式管理MyData的一组对象,例如,基于key1或key2(但不是两者)快速查找相应的对象。满足此要求的一种方法是分别根据这两个键构建两个不同的RB树(或哈希表)。在C/C++中,数据不需要复制,因为我们只需要记录对象的指针

在上面的假设示例中,关键的一点是我们有一组相同类型的数据,我们可以通过两种不同的数据结构来组织它,而不必用命令式语言复制数据。我想知道纯函数式编程如何在不复制数据的情况下有效地满足这一要求。为了使其更通用或更具挑战性,这两个数据结构可能不是同一类型。例如,一个可以是rb树,另一个可以是哈希表

如果可能,请在Haskell中布局您的解决方案

PS:作为函数式编程的新手,我不禁想知道如何在纯函数式编程中实现命令式编程的一些技巧。我知道有时候这毫无意义。如果有人觉得这个问题也毫无意义,请详细说明理由


谢谢

这在函数式编程中通常也不是问题

data MyData = MyData
  { key1 :: ByteString
  , key2 :: Int
  , {- some data -} }

现在,我们可以通过测试MyData,使用
key1
作为键,或者使用
key2
作为索引,或者使用
Vector MyData
构建
HashMap。只有指向键的指针才会被复制,而记录甚至键本身都不会被复制。

Haskell或任何其他语言(命令式或函数式)没有理由在默认情况下不存储指向不可变对象(尤其是大于指针的对象)的引用/指针,除了优化的特定原因,例如内存布局或功能代码被重写时,例如编译器在引擎盖下重写以提高性能


换句话说,没有什么理由不假设Haskell(或任何其他现代语言)能够像C一样有效地处理此问题。

您是否可以在此处使用union,打算在MyData结构中使用key1或key2?否。如果您使用key1搜索对象,您可能还想知道对象对应的key2值是多少。您只想查找值吗?或者也修改它们?变异确实会使功能设置变得更复杂。在命令式语言中,更改会自动在两个结构的共享值之间传播,至少在函数方法中不是这样的,如果你不使用一些特殊的数据结构。@Bakuriu:在函数编程中也不需要这种变化传播。你是说无论MyData有多复杂,函数编程编译器都能自动识别包含相同数据的对象吗?@YanZhu,没有。但是如果你计算了一些东西,然后把它放在两个不同的数据结构中,每个(通常)都只保存一个指向它的指针。@YanZhu通常不会这样做,没有。但是,与语言不同,语言的可变性是标准,复制是唯一安全的事情,在Haskell中,几乎没有任何操作会创建一段数据的副本(这毕竟是无法更改的!)。@YanZhu它与命令式编程没有太大区别。例如,使用
(“hel”++“lo”,“hel”++“lo”)
可能会分配两个字符串,而(x,x)
中的
让x=“hel”++“lo”可能只分配一个字符串。如果两次使用构造函数构建两个
MyData
值,则(很可能)使用两个副本。但是仅仅传递一些值是不会复制它的,不管它有多复杂,而且只传递一个指针。@dfeur我理解你的意思。谢谢