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.

Comments
Nothing yet. Say the first thing.
Sign in to join the conversation.