Clojure:地图列表的地图...如何纠缠匿名数据结构

时间:2012-01-13 23:46:10

标签: clojure defensive-programming

大家好:在java中,我们都有使用ide来“遍历”复杂数据类型深度的经验:

dog.getCollar().getCollarTag().getName(); 

然而,在Clojure中,由于缺乏静态类型,这变得非常简单。我们如何“防御”或反对可能来自嵌套数据结构的复杂事件?

1)对clojure数据结构深度的可取“限制”?

2)处理非常深层嵌套的数据结构的常用习惯用法,它可以防止 错误,如误认为地图列表,或未能正确降低/大写变量名称?

请原谅我,如果我在这里听起来有点偏离范例......可能是这样的错误可以通过在REPL中不断测试来有效地抑制。但是,我想知道是否还有其他在编译时确保代码尽可能正确的方法(即单元测试,IDE / emacs插件等)

5 个答案:

答案 0 :(得分:6)

关键字是你的朋友

(def my-animals  { :dog {:collar {:tag {:name "fido"}}}})

尝试坚持使用地图,因为它们更具有自我描述性 然后先使用线程和..

进行播放
(-> my-animals :dog :collar :tag :name)

并利用关键字也是在地图中看起来自我的功能这一事实。

当您在具有代码完成功能的IDE中工作时,它会解析代码,然后构建有关该代码的数据,然后解析该数据以生成它的建议。如果你的数据是自我声明的(它可以是“读取”),那么即使没有IDE,你也可以得到它。

ps:这导致关于“代码就是数据”的标准咆哮已经被比我更聪明的人多次表达过了:)

答案 1 :(得分:3)

在REPL中测试函数的正确性是一个好的开始。改进的一个好方法是单元测试,也许还有前后条件的使用(http://objectcommando.com/blog/2010/03/07/design-by-contract-with-clojure/).

使用关键字时,您的示例可以转换为(get-in dog [:collar :tag :name])。并使用assoc-inupdate-in进行“修改”。

答案 2 :(得分:2)

有一个很棒的图书馆,我发现在这方面真的很有帮助,这是来自制作棱镜的人的Schema library。它提供了一种为嵌套数据结构添加可选类型的方法,例如您在问题中引用的数据结构。这可以在运行时(或仅在测试时)强制执行,以验证函数的输入。此外,它还可以作为很好的文档,描述函数对其输入的假设(这不是一件小事)。

答案 3 :(得分:1)

链接的getter通常违反了Law of Demeter。在这样做时,您将代码耦合到整个数据结构,这可能是棘手而复杂的。在函数式语言中,clojure使用递归和序列处理更自然地保持简单和惯用。所以:

  1. 告诉,不要问。而不是要求“狗的衣领标签的名称......”试着要求狗对象或高级功能做你想做的事。
  2. 正如ponzao所说,测试,测试和测试。测试repl以探索您的选项并将小单元测试编写为

答案 4 :(得分:1)

How do we "defend" or Clojure against complexites that might arrive from nested data structures?

你做不到。这是这种语言的失败之一。如果你想要静态打字,那么clojure不是你的事。很多人会建议使用嵌套映射,这些映射很慢,根本不提供任何安全性,也不是数据类型。 Map是一种数据类型,嵌套映射不是,它们是伪装对象。就像javascript一样,clojure要求程序员跟踪各种数据的实际内容,因为Clojure中的数据片段是5种不同数据结构的组合,而不是数据结构本身。