file->sexp-list で遊ぶ
こんな風な関数を定義しておいて、
(use file.util) (use util.match) (use util.list) (use gauche.sequence) (use gauche.collection) (define (sexp-hist sexp-list) (define (hist exp ht) (cond ((null? exp) ht) ((pair? exp) (hist (car exp) ht) (hist (cdr exp) ht)) (else (if (hash-table-exists? ht exp) (hash-table-put! ht exp (+ (hash-table-get ht exp) 1)) (hash-table-put! ht exp 1))))) (let1 ht-result (make-hash-table) (hist sexp-list ht-result) ht-result)) (define (hist sexp-list) (let* ((ht (sexp-hist sexp-list)) (alist (hash-table->alist ht))) (sort alist (lambda (x y) (> (cdr x) (cdr y)))))) (define (hist-file file) (let1 sexp-list (file->sexp-list file) (hist sexp-list)))
こんな感じで遊ぶ。
;; gauche のコンパイラ本体を見てみる gosh> (define gh (hist-file "/Users/cranebird/Documents/Download/Gauche-0.8.14/src/compile.scm")) gh gosh> (length gh) 1163 ;; シンボルは1163種。 gosh> (subseq gh 0 50) ((iform . 652) (cenv . 321) (ccb . 306) (quote . 254) (form . 252) (unquote . 242) (define . 208) (renv . 200) (ctx . 173) (args . 164) (else . 124) (if . 121) (car . 118) (let1 . 114) (#f . 110) (quasiquote . 100) (x . 99) (name . 99) (0 . 98) (+ . 96) (info . 94) (body . 92) ($*-src . 89) (pass1 . 87) (cdr . 80) (rec . 79) (error . 79) (i . 77) (r . 77) (1 . 76) (_ . 75) (y . 74) (let . 70) (match . 69) (list . 69) (pass3/rec . 65) (expr . 64) (V . 62) (obj . 61) (null? . 60) (penv . 59) (lvar . 59) (cond . 56) (cons . 55) (lambda . 55) (test . 55) (2 . 55) (has-tag? . 54) (exprs . 53) (and . 53)) ;; トップ50。人気?のあるのは iform。コンパイラがあつかうデータ構造だから当然か。ccb って何だろうなぁ。ctx はコンテキスト、らしい。
データさえ作れればタブ区切りファイルにできて、後は R でグラフ化。今は集計まで scheme 側でしているが、R 側にほぼ生データを渡す方がベターかも。
(with-output-to-file "result.tsv" (lambda () (for-each (lambda (s) (format #t "~s~a~s~%" (car s) #\tab (cdr s))) (hist-file "compiler.scm"))))
熟練した Lisper のコードと初心者のコードの頻度分布には何らかの差があるのでは。