Of course, the above doesn't memoize, so repeated calls to ftab!fname will return different ((iso ftb!fname ftb!fname) => t, (is ftb!fname ftb!fname) => nil) objects.
And of course, you're not supposed to write circular objects with the above.
And then someone will want to use temload and friends... hmm. Need a good way of abstracting the abstractions...
Then memoization will be done on the file-contents (ct and mt) tables instead of actual file-table objects.
It would be useful also to have non-memoized versions, accessible via 'nocache:
(def grep* (rex path)
(zap re rex)
(accum collect
(ontable k v (file-table path 'nocache)
(if (re-match rex v) (collect k)))))
'nocache would be useful for such cases where you want to scan through files but not cache their actual contents.
It might also be useful to store cached contents only for a certain time, to preserve memory (but then gc will get run anyway).
p.s. supporting tagged options will make an optional path argument difficult. I suppose I can check if the first argument is a string, though, and treat it as the path if it is.