Functional programming 计算纯函数式语言中的字节频率

Functional programming 计算纯函数式语言中的字节频率,functional-programming,Functional Programming,如果我们有任务: 给定一个二进制数据块,计算其中字节的频率 在C语言中,即使对于较大的二进制块,答案也很简单,速度也相当快如何在没有副作用的情况下用纯函数式语言实现此功能? 例如,如果您编写了一个函数,该函数接受每个字节和字节列表的其余部分的频率计数,并返回修改后的频率计数,那么对于100M字节的数据集,它将不得不做大量的工作 此外,如果您对数据进行排序,然后以某种方式计算后续相同值字节的数量,那么排序本身将花费大量时间 有没有一种合理的方法来实现这一点?最简单的方法就是传入并返回将字节映射到计

如果我们有任务:

给定一个二进制数据块,计算其中字节的频率

在C语言中,即使对于较大的二进制块,答案也很简单,速度也相当快如何在没有副作用的情况下用纯函数式语言实现此功能?

例如,如果您编写了一个函数,该函数接受每个字节和字节列表的其余部分的频率计数,并返回修改后的频率计数,那么对于100M字节的数据集,它将不得不做大量的工作

此外,如果您对数据进行排序,然后以某种方式计算后续相同值字节的数量,那么排序本身将花费大量时间


有没有一种合理的方法来实现这一点?

最简单的方法就是传入并返回将字节映射到计数的数据结构。这可能会实现为某种树(因为据我所知,这是从标准库容器中得到的)。在纯函数式编程中,当您在树中传递时,需要返回一个新的树,并且只在一个节点中存在差异,则返回的树最终与原始树共享几乎所有的结构和数据

在遍历树以获得计数时会有一些开销,但由于您正在计算字节数,因此树的长度仅小于256个元素,因此开销为log(255),这是一个常量。对于大数据集,它不会变大——它不会改变算法的复杂度。事实上,即使在不共享的情况下使用最大可能的开销来复制完整的256个条目的计数数组,这也是正确的

如果您想对此进行优化,可以利用这样一个事实,即除了作为下一组计数计算的一部分之外,永远不需要“中间”频率计数。这意味着您可以使用各种技术让实现使用破坏性更新,即使您还在语义上编写功能代码。Haskell中的
STref
基本上允许您手动执行此操作


理论上,编译器可能会注意到您正在用一个新的值替换一个不再需要的值,因此它可以为您进行适当的更新。我不知道目前是否有任何实际的生产就绪编译器能够进行此优化。

实现此优化的直接方法确实是传入并返回将字节映射到计数的数据结构。这可能会实现为某种树(因为据我所知,这是从标准库容器中得到的)。在纯函数式编程中,当您在树中传递时,需要返回一个新的树,并且只在一个节点中存在差异,则返回的树最终与原始树共享几乎所有的结构和数据

在遍历树以获得计数时会有一些开销,但由于您正在计算字节数,因此树的长度仅小于256个元素,因此开销为log(255),这是一个常量。对于大数据集,它不会变大——它不会改变算法的复杂度。事实上,即使在不共享的情况下使用最大可能的开销来复制完整的256个条目的计数数组,这也是正确的

如果您想对此进行优化,可以利用这样一个事实,即除了作为下一组计数计算的一部分之外,永远不需要“中间”频率计数。这意味着您可以使用各种技术让实现使用破坏性更新,即使您还在语义上编写功能代码。Haskell中的
STref
基本上允许您手动执行此操作


理论上,编译器可能会注意到您正在用一个新的值替换一个不再需要的值,因此它可以为您进行适当的更新。我不知道目前是否有任何实际生产就绪的编译器能够进行此优化。

可以使用256*n位的大整数进行计数,其中n是计算预期数据量所需的最大位数。可以使用256*n位的大整数进行计数,其中n是计算预期数据量所需的最大位数。