【问题标题】:Do I need to understand how Haskell represents data to be able to write good Haskell programs?我是否需要了解 Haskell 如何表示数据才能编写好的 Haskell 程序?
【发布时间】:2010-10-05 08:52:42
【问题描述】:

我正在从 Java 背景学习 Haskell。当我编写 Java 时,我觉得我对对象在内存中的布局方式以及由此产生的后果有了深刻的理解。例如,我确切地知道java.lang.Stringjava.util.LinkedList 是如何工作的,因此我知道应该如何使用它们。有了 Haskell,我有点迷路了。例如,(:) 是如何工作的?我应该关心吗?是在某处指定的吗?

【问题讨论】:

  • 这是一个很好的问题,因为我看到人们用 !正是因为这个原因。
  • 一般来说,您也不需要了解 Java 类的内部结构(解耦、信息隐藏、封装......)。
  • @musiKk 我同意您不需要阅读源代码,但我认为从广义上了解某些东西是如何实现的会有所帮助。例如,LinkedList 和 ArrayList 之间的区别很容易理解,因为名称强烈暗示了实现,我不必查阅文档来发现方法是 O(1) 还是 O(n) 或其他。如果你只是给我一个List,不看文档我不知道操作会如何执行。
  • Haskell 中的所有数据都被定义为向外展开的树......所以对于如何实现一个简单的列表确实有一个显而易见的选择:单链表。如果您在各种类似的 monad 中工作,您可以使用可变数组来做事,但这是一个相当高级的话题。

标签: java data-structures compiler-construction haskell heap-memory


【解决方案1】:

简短的回答是否定的。在 Haskell 中编程时,您应该将数据结构视为纯数学对象,而不必担心它们在内存中的表示方式。这样做的原因是,在没有副作用的情况下,除了创建它的函数和可用于提取构造它的更简单部分的函数之外,实际上没有任何 to 数据.

要查看有关 (:) 等数据构造函数或任何其他术语的信息,请在 GHCi 中使用 :type(或简称为 :t)命令:

:Prelude> :type (:)
(:) :: a -> [a] -> [a]

这告诉您(:) 构造函数(读作“cons”)接受任何类型的值和相同类型的列表,并返回相同类型的列表。您还可以使用:info 命令获得更多信息。这将向您展示数据定义的样子:

Prelude> :info (:)
data [] a = ... | a : [a]   -- Defined in GHC.Types
infixr 5 :

这告诉您(:) 是将元素添加到现有列表的构造函数。

我还强烈推荐Hoogle 不仅可以按名称查找内容,还可以进行反向搜索;你知道你正在寻找的函数的签名,并想知​​道是否有人已经为你编写了它。 Hoogle 很好,因为它提供了描述和示例用法。

归纳数据的形状

我在上面说过,知道数据在内存中的表示并不重要……但是,您应该了解正在处理的数据的形状,以避免性能不佳决定。 Haskell 中的所有数据都是归纳定义的,这意味着它具有树状的形状,可以递归地向外展开。您可以通过查看数据的定义来判断数据的形状;一旦你知道如何阅读,它的性能特征就没有什么隐藏的了:

data MyList a = Nil | Cons a (MyList a)

从定义中可以看出,获得新的MyList 的唯一方法是通过Cons 构造函数。如果你多次使用这个构造函数,你最终会得到大致这种形状的东西:

(Cons a5 (Cons a4 (Cons a3 (Cons a2 (Cons a1 Nil)))))

它只是一棵没有树枝的树,这就是列表的定义!获得a1 的唯一方法是依次弹出每个Conss;因此访问最后一个元素是O(n),而访问头部是常数时间。一旦您可以根据数据结构的定义对数据结构进行这种推理,您就大功告成了。

【讨论】:

  • +1 仅适用于 Hoogle。每个 Haskell 程序员都应该知道并使用它。这是一个很棒的工具。
  • 可能还值得指出的是,仅在一个地方经常(?总是?)使用的值(例如列表)实际上并不存在 --- 生产和消费功能融合在一起一起跳过列表表示。
  • 绝对精彩的描述。
【解决方案2】:

简短的回答是“不”,您不需要了解数据布局——不过,了解复杂性会很有用。

然而,要编写高度优化的 Haskell 程序,对堆中数据结构的形状有很好的工作知识是必不可少的。 "vacuum" 可以帮助解决这个问题,它可以在布局时呈现 Haskell 数据结构的图表。

一些例子:

$ view "hello"

$ view (IntMap.fromList $ zip [1..10] [1..])

这是一个关于如何使用该工具的简短视频:http://www.youtube.com/watch?v=X4-212uMgy8

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多