代码之家  ›  专栏  ›  技术社区  ›  Rob Lachlan

在Clojure中,何时应该使用记录或向量来表示异构节点类型的树?

  •  6
  • Rob Lachlan  · 技术社区  · 14 年前

    对于表示由不同节点类型组成的树,哪一种是更好的惯用clojure实践:

    答。使用deftype或defrecord定义的几种不同类型的记录生成树:

    (defrecord node_a [left right])
    (defrecord node_b [left right])
    (defrecord leaf [])
    
    (def my-tree (node_a. (node_b. (leaf.) (leaf.)) (leaf.)))
    

    B。用向量构建树,用关键字指定类型:

    (def my-tree [:node-a [:node-b :leaf :leaf] :leaf])
    

    我看到的大多数clojure代码似乎都倾向于使用通用数据结构(向量、映射等),而不是数据类型或记录。举一个例子,Hiccup使用vector+关键字方法非常好地表示html。

    什么时候我们应该选择一种风格而不是另一种?

    2 回复  |  直到 14 年前
        1
  •  3
  •   Brian Carper    14 年前

    你可以把任意多的元素放到一个向量中。记录有一组字段。如果要将节点限制为只有N个子节点,则记录可能是好的,例如,生成一个二叉树,其中一个节点必须只有一个左节点和一个右节点。但是对于HTML或XML之类的东西,您可能希望支持任意数量的子节点。

    使用向量和关键字意味着“扩展”支持的节点类型集非常简单,只需在向量中放入一个新关键字即可。 [:frob "foo"] 即使它的作者从来没有听说过起泡,在打嗝是可以的。使用记录,您可能必须为每个节点类型定义一个新记录。但是,这样做的好处是可以捕捉错别字和验证子节点。 [:strnog "some bold text?"] 不会打嗝的,但是 (Strnog. "foo") 将是编译时错误。

    向量是Clojure的基本数据类型之一,您可以使用Clojure的内置函数来操作它们。想延长你的树吗?只是 conj 在上面,或者 update-in

    似乎这部分可以归结为动态与静态的争论。就我个人而言,我会走动态(矢量+关键字)路线,除非对使用记录的好处有特殊需要。这样编写代码可能更容易,而且对用户来说也更灵活,但代价是用户更容易陷入混乱。但是Clojure的用户可能已经习惯了必须定期处理危险武器。Clojure在很大程度上是一种动态语言,保持动态通常是正确的做法。

        2
  •  3
  •   Alex Miller    14 年前

    1.2中的记录还没有完全“完成”,但是自己构建这些东西非常容易。我们有一个 defrecord2 它增加了构造函数(newfoo)、字段验证、打印支持、pprint支持、通过zippers的树遍历/编辑支持等。

    我们使用它的一个例子是表示ast或执行计划,其中节点可能是Join、Sort等。

    向量更适合于创建字符串之类的东西,在字符串中,每个节点可以放置任意数量的东西。如果您可以填充1+<p>s内部a<div>,那么您就不能创建一个包含:p字段的记录-这根本没有任何意义。在这种情况下,向量更加灵活和惯用。