I left graduate school decades ago, but I still love to read academic papers. The field of computer science reinvents its wheels constantly, but academic literature is a great way to mine existing ideas and avoid that problem. It's a way to "stand on the shoulders of giants."
For a long time, I maintained and carefully indexed a collection of actual printed papers. Once it reached the hundreds, that approach became too cumbersome. I ended up throwing away papers in order to avoid having too many, but often regretted doing that when some half-remembered idea popped up again in another context.
Now I have a crude system that meets my needs. I keep notes on the
most interesting papers using Org-mode files, and I keep my collection in a Git repo in purely digital form.
Every paper appears in the top-level directory, and there's a
subdirectory to-read/
for papers I haven't yet read. A little bit of automation helps, too.
Now managing almost two thousand papers is no problem.
Here's the Scheme program, papers
, I use for adding new papers:
#!/usr/local/bin/chibi-scheme -r ;;;; -*- mode: scheme -*- ;;;; Expect environment variable <p> to name a directory that holds ;;;; all papers, e.g. "papers/". A subdirectory "to-read/" that holds ;;;; unread papers must also exist. ;;;; Copy specified documents into "$p/" directory. ;;;; If <--to-read> is specified, copy them to "$p/to-read/", too. ;;;; If <--commit> is specified, use Git to commit each of the new ;;;; documents. Each document will be committed separately. It is an ;;;; error if any other file is already staged. (import (chibi filesystem) (chibi pathname) (only (chibi process) exit process->output+error+status) (scheme process-context) (scheme small) (scheme write) (only (srfi 1) any remove) (srfi 98) (only (srfi 130) string-join string-prefix?) (srfi 166 base)) (define (echo . rest) (apply show #true rest) (show #true nl)) (define (echo-command command) (apply echo (list "command: " (string-join command " ")))) (define (usage program) (echo "Usage: " (path-strip-directory program) " [--commit] [--to-read] <pathname> ..." nl nl "Environment variable p must be set to a directory for holding papers." nl "It must have a subdirectory called \"to-read/\"." nl)) (define (run command) (let* ((out+err+status (process->output+error+status command)) (stdout (car out+err+status)) (stderr (cadr out+err+status)) (status (caddr out+err+status))) (unless (zero? status) (echo-command command) (write-string stderr) (write-string stdout) (exit 1)))) (define (run/assert command message) (unless (zero? (caddr (process->output+error+status command))) (echo-command command) (echo message) (exit 1))) (define (act document papers commit? to-read?) (let ((filename (path-strip-directory document))) (link-file document (path-resolve filename papers)) (when commit? (run `("git" "add" ,filename))) (when to-read? (let ((place (path-resolve filename (path-resolve "to-read" papers)))) (symbolic-link-file (path-resolve filename "..") place) (when commit? (run `("git" "add" ,place))))) (when commit? (run `("git" "commit" "-m" ,filename))))) (define (switch? string) (string-prefix? "--" string)) (define (main arguments) (let* ((program (car arguments)) (options (cdr arguments)) (papers (or (get-environment-variable "p") (begin (usage program) (exit 1)))) (valid-switches '("--commit" "--help" "--to-read"))) (cond ((member "--help" options) (usage program) (exit 0)) ((any (lambda (a) (and (switch? a) (not (member a valid-switches)))) options) (usage program) (exit 1))) (let* ((commit? (member "--commit" options)) (to-read? (member "--to-read" options)) (cwd (current-directory)) (documents (map (lambda (f) (path-resolve f cwd)) (remove switch? options)))) (when (null? documents) (usage program) (exit 1)) (change-directory papers) (when commit? (run/assert `("git" "diff" "--cached" "--quiet") "Error: Files already staged.")) (for-each (lambda (f) (act f papers commit? to-read?)) documents))))
For example, to add one paper, including a copy in to-read/
, commiting it to the repo:
papers --commit --to-read /tmp/aim-349.pdf
I use MIT Scheme for most of my Scheme hacking, but Alex Shinn's Chibi Scheme is wonderful for implementing this kind of tool. It's small, R7RS-Small-compliant, and has many useful libraries. Thank you, Alex!
Fixed on Wed 29 May 2024 to handle relative pathnames.