Recursion 如何使用scheme查找目录树中的文件?

Recursion 如何使用scheme查找目录树中的文件?,recursion,scheme,racket,mutual-recursion,Recursion,Scheme,Racket,Mutual Recursion,我正在尝试编写一个函数find,它使用一个目录树和一个文件名,并确定一个同名文件是否出现在目录树中。我所写的内容可以处理树的第一级(读取!)中的文件,但无法在中进一步“查看”文件。知道文件是否不在树中的唯一方法是检查每个目录和文件,但有些目录没有文件,有些目录没有目录,但有些目录有。我所写的do far对于我知道在树中的文件返回false。我不知道如何写出错误的条件 (define-struct dir (name dirs files)) (define-struct file (name s

我正在尝试编写一个函数find,它使用一个目录树和一个文件名,并确定一个同名文件是否出现在目录树中。我所写的内容可以处理树的第一级(读取!)中的文件,但无法在中进一步“查看”文件。知道文件是否不在树中的唯一方法是检查每个目录和文件,但有些目录没有文件,有些目录没有目录,但有些目录有。我所写的do far对于我知道在树中的文件返回false。我不知道如何写出错误的条件

(define-struct dir (name dirs files))
(define-struct file (name size content))

(define fs (make-dir 'TS
                     (list (make-dir 'Text empty
                                     (list
                                      (make-file 'part1 99 empty)
                                      (make-file 'part2 52 empty)
                                      (make-file 'part3 17 empty)))
                           (make-dir 'Libs
                                     (list
                                      (make-dir 'Code empty
                                                (list
                                                 (make-file 'hang 8 empty)
                                                 (make-file 'draw 2 empty)))
                                      (make-dir 'Docs empty
                                                (list
                                                 (make-file 'read! 19 empty)))) (list)))
                     (list (make-file 'read! 10 empty))))

(define (find fs name)
  (cond
    [(not (empty? (dir-dirs fs)))
    (dp (dir-dirs fs) name)]
    [(not (empty? (dir-files fs)))
     (fc (dir-files fs) name)]
    [else false]))

(define (dp dirs name) ;consumes lists of directories
  (cond
    [(empty? dirs) false] ;I don't know what else to put here but false
    [else (find (first dirs) name)
          (dp (rest dirs) name)]))

(define (fc files name) ;consumes lists of files
  (cond
    [(empty? files) false]
    [(symbol=? name (file-name (first files))) true]
    [else (fc (rest files) name)]))
以下是解决方案(请参见代码中的注释):


数据定义 例子 模板 测验 功能
如果我们将此数据定义用于Dir,则可以使用列表抽象:

; A Dir is a structure: 
;   (make-dir Symbol [List-of Dir] [List-of File])

; Dir Symbol -> Boolean
; does d have a file with the name filename?
(define (dir-find d filename)
  (or (dir*-find (dir-dirs d) filename) (file*-find (dir-files d) filename)))

; File Symbol -> Boolean
; does file f has the name filename?
(define (file-find f filename)
  (symbol=? (file-name f) filename))

; Dir* Symbol -> Boolean
; does d* have a file with the name filename?
(define (dir*-find d* filename)
  (ormap (λ (d) (dir-find d filename)) d*))

; File* Symbol -> Boolean
; does f* have a file with the name filename?
(define (file*-find f* filename)
  (ormap (λ (f) (file-find f filename)) f*))
我们还可以使用local的强大功能删除filename参数

; Dir Symbol -> Boolean
; does d have a file with the name filename?
(define (dir-find d filename)
  (local (; Dir -> Boolean
          ; does d have a file with the name filename?
          (define (dir-find-lcl d)
            (or (dir*-find (dir-dirs d)) (file*-find (dir-files d))))

          ; File -> Boolean
          ; does file f has the name filename?
          (define (file-find f)
            (symbol=? (file-name f) filename))

          ; Dir* -> Boolean
          ; does d* have a file with the name filename?
          (define (dir*-find d*)
            (ormap dir-find-lcl d*))

          ; File* -> Boolean
          ; does f* have a file with the name filename?
          (define (file*-find f*)
            (ormap file-find f*)))
    (dir-find-lcl d)))
事实上,可以进一步简化:

; Dir Symbol -> Boolean
; does d have a file with the name filename?
(define (dir-find d filename)
  (or (ormap (λ (d) (dir-find d filename)) (dir-dirs d))
      (ormap (λ (f) (symbol=? (file-name f) filename)) (dir-files d))))
; Dir -> ...
(define (dir-temp d)
  (... (dir-name d) ... (dir*-temp (dir-dirs d)) ... (file*-temp (dir-files d)) ...))

; File -> ...
(define (file-temp f)
  (... (file-name f) ... (file-size f) ... (file-content f) ...))

; Dir* -> ...
(define (dir*-temp d*)
  (cond
    [(empty? d*) ...]
    [else (... (dir-temp (first d*)) ... (dir*-temp (rest d*)) ...)]))

; File* -> ...
(define (file*-temp f*)
  (cond
    [(empty? f*) ...]
    [else (... (file-temp (first f*)) ... (file*-temp (rest f*)) ...)]))

(check-expect (dir-find ts 'hang) true)
(check-expect (dir-find ts 'part1) true)
(check-expect (dir-find ts 'part99) false)
(check-expect (dir-find text 'read!) false)
(check-expect (dir-find text 'part2) true)
(check-expect (dir-find docs 'read!) true)
(check-expect (dir-find docs 'draw) false)
; Dir Symbol -> Boolean
; does d have a file with the name filename?
(define (dir-find d filename)
  (or (dir*-find (dir-dirs d) filename) (file*-find (dir-files d) filename)))

; File Symbol -> Boolean
; does file f has the name filename?
(define (file-find f filename)
  (symbol=? (file-name f) filename))

; Dir* Symbol -> Boolean
; does d* have a file with the name filename?
(define (dir*-find d* filename)
  (cond
    [(empty? d*) false]
    [else (or (dir-find (first d*) filename) (dir*-find (rest d*) filename))]))

; File* Symbol -> Boolean
; does f* have a file with the name filename?
(define (file*-find f* filename)
  (cond
    [(empty? f*) false]
    [else (or (file-find (first f*) filename) (file*-find (rest f*) filename))]))
; A Dir is a structure: 
;   (make-dir Symbol [List-of Dir] [List-of File])

; Dir Symbol -> Boolean
; does d have a file with the name filename?
(define (dir-find d filename)
  (or (dir*-find (dir-dirs d) filename) (file*-find (dir-files d) filename)))

; File Symbol -> Boolean
; does file f has the name filename?
(define (file-find f filename)
  (symbol=? (file-name f) filename))

; Dir* Symbol -> Boolean
; does d* have a file with the name filename?
(define (dir*-find d* filename)
  (ormap (λ (d) (dir-find d filename)) d*))

; File* Symbol -> Boolean
; does f* have a file with the name filename?
(define (file*-find f* filename)
  (ormap (λ (f) (file-find f filename)) f*))
; Dir Symbol -> Boolean
; does d have a file with the name filename?
(define (dir-find d filename)
  (local (; Dir -> Boolean
          ; does d have a file with the name filename?
          (define (dir-find-lcl d)
            (or (dir*-find (dir-dirs d)) (file*-find (dir-files d))))

          ; File -> Boolean
          ; does file f has the name filename?
          (define (file-find f)
            (symbol=? (file-name f) filename))

          ; Dir* -> Boolean
          ; does d* have a file with the name filename?
          (define (dir*-find d*)
            (ormap dir-find-lcl d*))

          ; File* -> Boolean
          ; does f* have a file with the name filename?
          (define (file*-find f*)
            (ormap file-find f*)))
    (dir-find-lcl d)))
; Dir Symbol -> Boolean
; does d have a file with the name filename?
(define (dir-find d filename)
  (or (ormap (λ (d) (dir-find d filename)) (dir-dirs d))
      (ormap (λ (f) (symbol=? (file-name f) filename)) (dir-files d))))