Rob*_*lan 6 tree types idioms clojure
哪个是更好的惯用语法练习,用于表示由不同节点类型组成的树:
A.使用deftype或defrecord定义几种不同类型记录中的树构建:
(defrecord node_a [left right])
(defrecord node_b [left right])
(defrecord leaf [])
(def my-tree (node_a. (node_b. (leaf.) (leaf.)) (leaf.)))
Run Code Online (Sandbox Code Playgroud)
B.用向量构建树,用关键字指定类型:
(def my-tree [:node-a [:node-b :leaf :leaf] :leaf])
Run Code Online (Sandbox Code Playgroud)
我看到的大多数clojure代码似乎都支持使用通用数据结构(向量,映射等),而不是数据类型或记录.Hiccup,举一个例子,非常好地使用vector + keyword方法表示html.
什么时候我们应该比另一种更喜欢一种风格?
您可以根据需要将任意数量的元素放入向量中。一条记录有一定数量的字段。如果你想限制你的节点只有N个子节点,记录可能会很好,例如,当一个二叉树时,一个节点必须只有一个左和右。但对于 HTML 或 XML 之类的内容,您可能希望支持任意数量的子节点。
使用向量和关键字意味着“扩展”支持的节点类型集就像将新关键字放入向量中一样简单。 [:frob "foo"]
即使它的作者从未听说过 frobing,在 Hiccup 中也可以。使用记录,您可能必须为每个节点类型定义一个新记录。但随后您将获得捕获拼写错误和验证子节点的好处。 [:strnog "some bold text?"]
不会被 Hiccup 捕获,但(Strnog. "foo")
会是一个编译时错误。
向量是 Clojure 的基本数据类型之一,您可以使用 Clojure 的内置函数来操作它们。想扩展你的树吗?就conj
在上面,或者update-in
,或者其他什么。您可以通过这种方式逐步构建您的树。对于记录,您可能会陷入构造函数调用的困境,否则您必须为构造函数编写大量包装函数。
看来这在一定程度上可以归结为动态与静态的争论。就我个人而言,我会采用动态(向量+关键字)路线,除非有特定需要使用记录的好处。以这种方式编码可能更容易,并且对用户来说更灵活,但代价是用户更容易最终陷入混乱。但 Clojure 用户可能习惯于定期处理危险武器。Clojure 在很大程度上是一种动态语言,保持动态通常是正确的做法。