golche

object-applyでgorubyっぽいことをする試み。

(extend srfi-1 util.combinations)

(define (matching-symbols key)
  (define (pack-capture-sizes mat)
    (fold (lambda (i r) (+ (string-size (mat i)) (* r 32)))
          0 (iota (- (rxmatch-num-matches mat) 1) 1)))
  (let ([results '()]
        [matcher (string->regexp
                  (regexp-replace-all
                   #/./
                   (x->string key)
                   (lambda (m)
                     #`"(.*?),(regexp-quote (m))")))])
    (for-each
     (lambda (mod)
       (hash-table-for-each
        (module-table mod)
        (lambda (sym val)
          (let* ([s (symbol->string sym)]
                 [m (rxmatch matcher s)])
            (if m (push! results
                         (list (pack-capture-sizes m) s sym)))))))
     (all-modules))
    (map! caddr
          (sort! results
                 (lambda (x y)
                   (or (< (car x) (car y))
                       (and (= (car x) (car y))
                            (string<? (cadr x) (cadr y)))))))))

(define (shortest-abbreviation key)
  (set! key (x->string key))
  (let* ([lst (matching-symbols key)]
         [sym (string->symbol key)])
    (if (or (null? lst) (not (memq sym lst)))
        #f
        (call/cc
         (lambda (cnt)
           (for-each
            (lambda (n)
              (combinations-for-each
               (lambda (c)
                 (set! c (list->string c))
                 (if (eq? sym (car (matching-symbols c)))
                     (cnt c)))
               (string->list key) n))
            (iota (string-size key) 1)))))))

(define-method object-apply ((kwd <keyword>))
  (let ([sym (string->symbol (keyword->string kwd))]
        [mod (current-module)])
    (if (global-variable-bound? mod sym)
        (global-variable-ref mod sym)
      (let ([lst (matching-symbols sym)] [val #f])
        (if (null? lst) (error "golche: no match"))
        (set! val (global-variable-ref mod (car lst)))
        (eval `(define ,sym ,val) mod)
        (format (standard-error-port) "~s => ~s\n" val sym)
        val))))

(define-method object-apply ((kwd <keyword>) . arg)
  (apply (object-apply kwd) arg))
> gosh -I. -l golche.scm
gosh> (:mp(:nm)(:io 9))
#<subr number->string> => nm
#<closure iota> => io
#<subr map> => mp
("0" "1" "2" "3" "4" "5" "6" "7" "8")
gosh> (shortest-abbreviation 'shortest-abbreviation)
"sh"
gosh> (:sh 'regexp-replace-all*)
#<closure shortest-abbreviation> => sh
"r--*"

一応動いてるっぽい。
検索対象が多いのと関数名が長いせいでshortest-abbreviationはかなり遅い。