I have been reading "Higher Order Perl Programming" lately. One of the example of using higher order functions is a file system traversing. Given a directory as a starting point you call a user specified function for each of the files in the directory. In case you encounter a directory then do the same for all of its files and so on.
Here is the Scheme version of this functions:
(define (for-each-file path proc)
(cond
((file-directory? path)
(let ((names (directory-files path)))
(for-each (lambda (p)
(if (or (string=? p ".") (string=? p ".."))
'do-nothing
(let ((complete-path (string-append (file-name-as-directory path)
"/"
p)))
(for-each-file complete-path proc))))
names)))
(else (proc path))))
Then you can use it to display the list of HTML files in a given directoy with:
(for-each-file "." (lambda (f) (if (string=? ".html" (file-name-extension f)) (display f))))
Note that you may find all the Texinfo (filenames with extension ".texi") files in a directory with:
(for-each-file "." (lambda (f) (if (string=? ".texi" (file-name-extension f)) (display f))))
Note that you may do the same for all the Scheme or Perl or whatever file kind in a given directory. Is there not a pattern here ? Of course, you can come up with the following function:
(define (find-files-with-extension path extension) (for-each-file path (lambda (f) (if (string=? extension (file-name-extension f)) (display f)))))
Now you can simply call the function and pass it the desired file extension. Our examples now becomes:
(find-files-with-extension "." ".html") (find-files-with-extension "." ".texi") (find-files-with-extension "." ".scm") (find-files-with-extension "." ".pl")
Let's go a bit further. What happens if you want to name such functions. Something like:
(define (find-html-files path) (find-files-with-extension path ".html")) (define (find-texinfo-files path) (find-files-with-extension path ".texi")) (define (find-scheme-files path) (find-files-with-extension path ".scm"))
You can achieve the same result with a higher order procedure. Why don't we construct a builder function: give it an extension and it gives you a procedure for find all files having this extension in a directory.
(define (make-file-finder-with-extension extension) (lambda (path) (find-files-with-extension path extension)))
Now our specific procedures find-html-files, find-textinfo-files, find-scheme-files may be written like that:
(define find-html-files (make-file-finder-with-extension ".html")) (define find-texinfo-files (make-file-finder-with-extension ".texi")) (define find-scheme-files (make-file-finder-with-extension ".scm"))
Just give me an extension and I give you a functions for finding all files in a directory having this precise extension. Give me X and I give you a function that Y. Isn't it nice ?