到目前为止,我的知识水平是这样的,我已经完成了The Little Schemer而没有问题,而且我目前通过The Seasoned Schemer获得70%。我在脑海中想到了一些项目的想法,我希望通过这些项目来获得与Scheme合作的实际经验,但是(也许是因为我在整个职业生涯中主要使用OO语言)我仍然想知道如何我们可以用函数式语言(如Scheme)解决OO语言的一些相当基本的问题。
我不会将所有问题都推到一个stackoverflow问题中,而是随着时间的推移逐渐将它们剔除,并假设这些部分将落实到位,所以我实际上不需要其他问题的答案。
很明显,Scheme的东西就是列表。列表和列表列表。我习惯于能够存储包含可以快速检索的“属性”的列表(即散列),并且可以嵌套在另一个内部。
以递归方式传递文件系统中的文件和目录列表为例,如何在Scheme中处理这样的事情?我想你可以传递一种形式的数据结构:
'(("foo" (("bar.txt")
("zip.txt")
("button.txt")))
("other.txt")
("one-more" (("time.txt"))))
其中每个节点表示为列表的汽车,其子节点表示为其cdr的汽车中包含的另一个列表,因此上面是一个树结构:
foo/
bar.txt
zip.txt
button.txt
other.txt
one-more/
time.txt
或许有人会传递一个接受访问者的迭代器函数而不是进行某种深树遍历? (在知道何时切换目录方面,并不完全确定看起来如何)。
对于这类问题,是否存在一般模式,不仅仅是目录树,而是树结构(附带元数据)?
与面向对象的等价物相比,这是否会不可避免地变得非常繁琐?
答案 0 :(得分:6)
很明显,Scheme的东西就是列表。
传统上,是的。但是从R6RS开始,还有records个命名字段,这使得使用其他类型的数据结构更容易实现 lot 。实际的Scheme实现已有数十年,但它们从未标准化,因此语法各不相同。
对于这类问题,是否存在一般模式,不仅仅是目录树,而是树结构(附带元数据)?
是的,凭借你对“迭代器功能”的想法,你已经击中了头部。 (除了定义一个宏会更优雅,所以你可以说:
(for-each-label (x tree 'in-order)
(display x))
使用define-syntax
创建宏。)
答案 1 :(得分:6)
我在你的问题中看到了两个部分。
在标准R5RS中,大多数树实现使用向量来表示 树中的节点。对于二进制树,可能会定义一些 辅助函数:
(define (tree-left t) (vector-ref t 0))
(define (tree-right t) (vector-ref t 1))
(define (tree-value t) (vector-ref t 2))
(define (make-node l r v) (vector l r v))
(define (leaf? t) (eq? t #f))
在具有结构/记录的方案中,上述内容将替换为>
(define-struct tree (left right value))
(define (leaf? t) (eq? t #f))
如果支持结构的层次结构,可以写
(define-struct tree ())
(define-struct (leaf tree) ())
(define-struct (node tree) (left right value))
对于支持操作的模式匹配代码的方案 树看起来像ML和Haskell中的树处理代码。
我可以推荐HtDP中关于二叉搜索树的部分: http://htdp.org/2003-09-26/Book/curriculum-Z-H-19.html#node_sec_14.2
有几种方法。一种常见的方式是 提供给定目录产生的功能 可以产生一个的函数或序列 元素(文件或子目录)一次。这是避免 需要在内存中存储一个可能很大的文件树。
在Racket中,人们可以使用序列:
#lang racket
(for ([file (in-directory "/users/me")])
(displayln file))
R5RS中没有可用的目录遍历机制,但是 当然所有主要的实现都提供了某种方式 这样做。
BTW:确实,Scheme为单个链表提供了非常的良好支持,但是在实现功能数据结构时,由于更快的随机元素访问,使用向量甚至更好的结构通常更好。