はてなキーワード: eQとは
「勉強が出来る = 頭がいい」への違和感は「能力を測る基準の一つ」と「能力」をイコールで結んでしまっている事が原因でしょう。
つまり「100メートル走が早い = 足が速い」「リズム感がある = 音楽センスがある」「デッサンが上手い = 絵が上手」と言っているようなものです。
世の中でそのことを否定する意見が多いのは負け犬の遠吠えというよりも、世の中で求められている「頭の良さ」と「学力」の乖離が大きいことが原因でしょう。
そのため企業は、より精度の高い判断基準を求めて「SPIテスト」を行ったり、世の中が「EQ」や「地頭力」などの新基準探しに夢中になっていたりするのです。
ちなみに、個人的な感想としては「学力」と「頭がいい」には弱い相関関係は有ると考えていますが個人対個人のレベルで使用するためには精度が低いと思っています。
不思議なんだけど、なんでPerfumeを叩こうという人は
小難しいこと書くんだろうね。
元増田の書いている内容って別に何も難しくないでしょ。
テクノロジカルな表現手法に対する嫌悪感を示しているだけの話。
この種の感情というのは特に珍しくない。昔からシンセ嫌いな人間とかもいるしね。
ただPerfumeの音楽クオリティが低いのはそこに原因があるわけではないんだ。
実は今の音楽業界では程度の差はあれ、誰も彼もがテクノロジカルな編集過程を経ている。
一見アコースティックなサウンドにナチュラルな歌声がのせられていたとしても、
さまざまな処理が施されている。
音程はAutotuneとかMelodyneで修正され、声が前に出るようにEQやコンプでコントロールされていたりする。
また空間的な広がりを醸成するためにリバーブやディレイなどで綿密にコントロールされていたりする。
音量だってサビは若干大きめになるよう持ち上がっていたりするくらいだ。
だからPerfumeというのは単にテクノロジカルな度合いが高いだけなのだ。
Perfumeがショボいのは、むしろトラックを作っている中田ヤスタカの表現の幅の薄さに由来する。
毎度同じようなコード進行にその上に載せられたワンパターンなメロディワーク。
リズムは大概ハウスのリズムだし実に引き出しの少なさを露呈してしまっている。
これはプロデューサーとしては致命的である。
小室哲哉やつんくが中田ヤスタカより一枚上手だったのは彼ら自身だけで完結しないからだ。
中田は全て自分で作ってしまう。したがって中田の脳内を出ないのだ。
だからいつでも新しいアイデアを投入することができるのだ。
アイデアさえあれば、後はアイデアを形にしてくれる人間に投げさえすればよい。
中田は違う。自分で表現可能な範囲内でしかアイデアを持つことが許されないわけだ。
もちろん彼が今後別の人間に投げるようになれば別だが。
こういうことはこれまで誰も突っ込んでこなかったが、
認識しておいたほうがよい事柄であるのでこの機会に明記しておく。
@oo[2, 5, 8, 11] = (' ', ' ', ' ', ' '); $xx[5] = ' '; for($s=4; $s < 201; $s++){ for($i = 2; $i <= ($s+1) / 2; $i++){ next if $i == 3; $j = $s - $i; &test_base($i, $j); &test_base($j, $i) if $i <=> $j; } print "$s\[$oo[$s]]\n" if $oo[$s] ne ''; $min = length $oo[$s] || 999; if($ox[$s] ne '' and length $ox[$s] < $min){ print "$s\[$ox[$s]>\n"; $min = length $ox[$s]; }if($xo[$s] ne '' and length $xo[$s] < $min){ print "$s<$ox[$s]]\n"; $min = length $xo[$s]; }if($xx[$s] ne '' and length $xx[$s] < $min){ print "$s<$xx[$s]>\n"; } } sub test_base{ my ($i, $j); ($i, $j) = @_; if($oo[$i] ne ''){ &test($oo[$i], $oo[$j], \$oo[$s]); &test($oo[$i], $xo[$j], \$oo[$s]); &test($oo[$i], $ox[$j], \$ox[$s]); &test($oo[$i], $xx[$j], \$ox[$s]); }if($ox[$i] ne ''){ &test($ox[$i], $oo[$j], \$oo[$s]); &test($ox[$i], $ox[$j], \$ox[$s]); }if($xo[$i] ne ''){ &test($xo[$i], $oo[$j], \$xo[$s]); &test($xo[$i], $xo[$j], \$xo[$s]); &test($xo[$i], $ox[$j], \$xx[$s]); &test($xo[$i], $xx[$j], \$xx[$s]); }if($xx[$i] ne ''){ &test($xx[$i], $oo[$j], \$xo[$s]); &test($xx[$i], $ox[$j], \$xx[$s]); } } sub test{ return if $_[1] eq ''; my($a, $b, $c, $tmp); ($a, $b, $c) = @_; $tmp = "$a$b"; ${$c} = $tmp if ${$c} eq '' or (length $tmp) < (length ${$c}); return; }
こういうときには、むしろEQの方が大切かと…
どうーでもいいーですよー。
どうでもいい話ー、聞いてください。
Perlというやつは一応内部的には数値か文字列かをちゃんと分けて変数の管理をしているのです。
でわ、現在ある変数が内部的に数値なのか?内部的に文字列なのか?判別しようと思ったらどうしますか?
こうしてみます。
my @data = ( 100, # 100は内部的に数値 '200' # 200は内部的に文字 ); foreach my $d ( @data ) { if( ($d ^ $d) eq '0' ){ print $d . " = It's numeric\n"; } else { print $d . " = It's string\n"; } }
同じ変数同士を排他的論理和(^)すると、その変数が数値の場合は0になり、その変数が文字列の場合は空文字になるのです。
なぜかって?そりゃ同じ値同士で排他的論理和したら必ず00000000になるでしょう?
で00000000は、数値なら数字の0だし、文字列なら制御コードのNUL文字になるので上記のような処理が成り立つというわけです。
あってますよね?
ってか判別できたからなんだというんだと問われたらぐうの音すら出ません。まったくもってどうでもいい話でした。
やってしまった・・・。
方針:
package SixtyLinesTemplate; use strict; use warnings; our $VERSION = '0.01'; sub convert { return unless defined(my $str = shift); $str =~ s{&}{&}gso; $str =~ s{<}{<}gso; $str =~ s{>}{>}gso; $str =~ s{\"}{"}gso; $str; } sub include_template { my $tmpl = shift; my %c = %{+shift}; eval convert_template($tmpl); die $@ if $@; } sub convert_template { my $tmpl = shift; my $cache = $tmpl.'.cache'; return scalar do { open my ($FH) , $cache; local $/; <$FH> } if ( -f $cache && (stat($tmpl))[9] <= (stat($cache))[9] ); my $out = do { open my ($FH) , $tmpl; local $/; <$FH> }; $out =~ tr/()/\x28\x29/; $out =~ s/\[%\s*(foreach|if|unless|end)\s*(.+?)\s*{?\s*%\]/");".(lc($1) eq 'end' ? '} print q(' : "$1 $2 { print q(")/ige; $out =~ s/\[%(.+?)%\]/);print $1; print q(/g; $out =~ s/\[#(.+?)#\]/);print SixtyLinesTemplate::convert($1); print q(/g; $out = 'print q('.$out.');'; open my ($FH) , '>' , $cache; print $FH $out; $out; } 1;
サンプルコード:
use SixtyLinesTemplate; my $context = { 'title' => 'Example', 'list' => [10,'<A&B>'] }; SixtyLinesTemplate::include_template('template.tmpl',$context);
サンプルテンプレート:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <title>[# $c{title} #]</title> </head> <body> <h1>[# $c{title} #]</h1> <table> [% foreach my $i (0..@{$c{list}}-1) %] <tr bgcolor="[% $i % 2 ? '#FFCCCC' : '#CCCCFF' %]"> <td>[% $i %]</td> <td>[# $c{list}[$i] #]</td> </tr> [% end %] </table> </body> </html>
出力例:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <title>Example</title> </head> <body> <h1>Example</h1> <table> <tr bgcolor="#CCCCFF"> <td>0</td> <td>10</td> </tr> <tr bgcolor="#FFCCCC"> <td>1</td> <td><A&amp;B></td> </tr> </table> </body> </html>
foreachんところが汚く見えるかもしれませんが、あれは添え字を取ろうとするとああなるんでご勘弁を。
普通にループするだけならforeach my $item (@$c{title}) でいけますゆえ。
あと存在しない変数とか使うと死んだり警告でたりするのでevalの前にno strictとno warningsをやった方がいいかもねぇ。
って何まじめに検証してんだ俺・・・orz
追記:
SixtyじゃなくてFortyだね。恥ずかし!
追追記:
でも&amp;の奴はちゃんと書いてるんだけども投稿すると勝手にエスケープされてしまってるんだよね。何でだろ?
ちなみにこのconvertの処理はCGI::Utilから拝借しました。
発祥: http://ex23.2ch.net/test/read.cgi/morningcoffee/1188654905/
Scheme という Lisp 語族の言語を用いて ℃-ute の相関関係をプログラムし、様々な角度から関係性を分析する手法を紹介していきます(ソースコードは最後に張ります)。
まずは、メンバー間の関係を「リスト」というデータ型で表現します。例えば「栞菜->愛理」という関係は
(kanna . airi)
という形で表すことができます。これに、「大好き」という情報を付加し、ついでにその関係の性質を数値化したものを加えると
((kanna . airi) (desc "大好き") (score . 1))
のようになり、関係図における一つの矢印の情報をデータ化できたことになります(暫定的に、好意は 1、良好・中立は 0、険悪は -1 の3段階で表すことにします)。
メンバー間の全ての関係性をこのデータ単位で定義し、データベース化しておくことで、色んな条件に基づいた検索やスコア計算などが可能となります。
ここで相関関係図における矢印を「リンク」と呼ぶことにして、あるメンバーから他のメンバーへどのようにリンクし、またリンクされているかを調べることができます。
(sort-nodes (number-list (from-links)))
結果:
((kanna . 6) (saki . 5) (maimi . 4) (erika . 3) (mai . 3) (chisato . 3) (airi . 2))
栞菜ちゃんがメンバー全員にリンクを張っていることが分かり、℃-ute ラブっぷりが伺えます。なっきーにも同様の事が言えます。例の「女の子が好き」発言を数値的に裏付ける結果と言えるかもしれません。
ただ、データ不足でリンク件数がまだ少ないのと、リンクの性質(好意/反感など)までは分からない点を考慮する必要があるでしょう。
同様に、リンクの終点の件数を調べてみます。
(sort-nodes (number-list (to-links)))
((chisato . 5) (erika . 5) (kanna . 4) (maimi . 4) (airi . 4) (mai . 3) (saki . 1))
えりかちゃんと千聖ちゃんが高ポイントです。メンバーからの人気や注目度の高さを示すデータですが、千聖ちゃんの場合敵対的なリンクが2件含まれている点に注意してください。
なっきーの被リンク数が極端に少ないですが、単純にデータ不足のためだと思われます。はぶら(ryとか言わないようにお願いします。
リンクに付随するスコアを計算することで、愛情の度合いを測ることができるのではないか、という考えに基づく研究です。
まず、全ての関係性を対象として、スコアがマイナスの関係を抽出してみます。
(filter-nodes (lambda (n) (< (score-relation n) 0)))
結果:
(((kanna . chisato) (desc "愛理に手出すんじゃねぇよ") (score . -1)) ((saki . chisato) (desc "愛理に手出すんじゃねぇよ") (score . -1)))
件数だけを得ると
(length (filter-nodes (lambda (n) (< (score-relation n) 0))))
2
僅か2件です。
良好・中立的な関係は
(length (filter-nodes (lambda (n) (= (score-relation n) 0))))
8
愛に満ちた関係は
(length (filter-nodes (lambda (n) (> (score-relation n) 0))))
16
非常に多いです。舞美ちゃんの「℃-ute同士でラブラブなんですよ」発言(例のラジオ)を数値的に裏付ける結果と言えるんじゃないでしょうか。
次に、メンバーごとのスコアを算出してみます。Lisp 的には以下のようにフィルタリングと畳み込み (fold) で計算することができます。例えば
(foldr (lambda (n acc) (+ (get-score n) acc)) 0 (filter-nodes (cut to? <> 'kanna)))
3
上式を一般化して一挙にメンバー全員に適用してみると
(sort-nodes (map (lambda (x) (cons x (score-loved x))) (all-members)))
結果:
((airi . 4) (kanna . 3) (mai . 2) (erika . 2) (maimi . 2) (saki . 1) (chisato . 0))
愛理ちゃんが好意を寄せられやすい傾向が伺えます。
今度は逆方向のスコアを計算してみると
(sort-nodes (map (lambda (x) (cons x (score-loving x))) (all-members)))
((kanna . 3) (maimi . 3) (chisato . 2) (airi . 2) (saki . 2) (mai . 1) (erika . 1))
まいまいとえりかちゃんが特に堅い・一途だという傾向を読み取ることができます。
今度は組み合わせ(カップリング)の評価です。
2点間相互のリンク・スコアを加算したものを「相性」と考えられるものとします。最大値 (互いに好意を寄せている場合の数値) は現在のスコアリング方式では 2 です。例えば
(score-between 'kanna 'airi)
の値は
2
となります。1 であれば一方通行と考えます。
関係性が未定義の場合もあるので 0 のものを除外して算出すると
(sort-nodes (filter (lambda (n) (not (= (cdr n) 0))) (map (lambda (n) (cons n (apply score-between n))) (all-combinations))))
(((chisato mai) . 2) ((chisato airi) . 2) ((airi kanna) . 2) ((saki kanna) . 2) ((kanna maimi) . 2) ((erika maimi) . 2) ((saki airi) . 1) ((saki erika) . 1) ((kanna mai) . 1) ((maimi airi) . 1) ((saki chisato) . -1) ((kanna chisato) . -1))
となります。若干ピンとこない部分もあるかも知れませんが、計算上は矛盾無くデータの内容を表しています。
(map (lambda (p) (find-relation (cons (caar p) (cadar p)) identity)) (filter (lambda (n) (= (cdr n) 1)) (map (lambda (n) (cons n (apply score-between n))) (all-combinations))))
(((kanna . mai) (desc "喰ってやるよ") (score . 1)) ((saki . airi) (desc "好き") (score . 1)) ((maimi . airi) (desc "良き妹") (score . 1)) ((saki . erika) (desc "彼氏にしたい") (score . 1)))
のようになります。
以上の調査を経て気になった問題点を列挙してみます。
特に最初の点に関して、「百合的」なるものの質的評価がなかなか難しいと感じました。例えば「大好き」も「良き妹」も同じ 1 と評価してしまっているのが妥当かどうか、といったことです。
また、スレにて与えられた情報を評価・分析する方法としては有効だとしても、逆方向のフィードバックの手段がなかなか見つからないというのが三つ目の問題です(技術力不足とも言います)。(注:画像化の方法が分かりました。追記参照)
最後に、プログラムのソースを示します。実行には PLT Scheme が必要です。文字コードは UTF-8 で保存した上で、(load "c-ute.ss") としてください。文字化けする場合はターミナルが UTF-8 を表示できるよう設定する必要があります。がんばってください。
c-ute.ss:
(require (lib "etc.ss") (lib "list.ss") (lib "26.ss" "srfi") (lib "delete.ss" "srfi" "1")) ;;; Utilities (define true? (compose not not)) (define (ignore _) #f) (define fif (case-lambda ((predicate consequent) (fif predicate consequent ignore)) ((predicate consequent alternative) (lambda (x) (if (predicate x) (consequent x) (alternative x)))))) (define (concat! xs) (apply append! xs)) (define (mapconcat f lst sep) (let lp ((str (f (car lst))) (lst (cdr lst))) (if (null? lst) str (lp (string-append str sep (f (car lst))) (cdr lst))))) (define (slice-string str len) (let lp ((res '()) (str str)) (if (<= (string-length str) len) (reverse! (cons str res)) (lp (cons (substring str 0 len) res) (substring str len))))) (define (break-string str len) (mapconcat identity (slice-string str len) "\\n")) ;; NOTE: input and output ports have to be either file-stream or #f ;; (i.e., cannot be a string port) (define (run exe opt in out) (let-values (((p p-i p-o p-e) (subprocess out in #f exe opt))) (subprocess-wait p) (close-input-port p-e))) ;;; Database ;; http://ja.wikipedia.org/wiki/%E2%84%83-ute (define names '((erika . "えりか") (maimi . "舞美") (saki . "早貴") (airi . "愛理") (chisato . "千聖") (mai . "舞") (kanna . "栞菜"))) (define (symbol->name sym) ((fif true? cdr) (assq sym names))) (define nodes '()) (define edges '()) (define (relate from to desc score) (let ((n (cons from to))) (or (find-relation n (lambda (r) (let ((d (assq 'desc r)) (s (assq 'score r))) (set-cdr! d (cons desc (cdr d))) (set-cdr! s (+ score (cdr s)))))) (begin (set! nodes (cons n nodes)) (set! edges (cons (cons n `((desc ,desc) (score . ,score))) edges)))))) (define (find-relation n k) ((fif true? k) (assoc n edges))) (define (related? x y) (find-relation (cons x y) (lambda (_) #t))) (define (from? n x) (eq? (car n) x)) (define (to? n x) (eq? (cdr n) x)) (define flip-relation (case-lambda ((n) (and (related? (cdr n) (car n)) (cons (cdr n) (car n)))) ((n k) ((fif true? k) (flip-relation n))))) (define (get-score n) (cdr (assq 'score n))) (define (get-description n) (cdr (assq 'desc n))) (define (describe-relation n) (find-relation n get-description)) (define (score-relation n) (or (find-relation n get-score) 0)) (define (print-node . ns) (for-each (cute find-relation <> (lambda (r) (display (format "| ~a => ~a (~a)~%" (caar r) (cdar r) (mapconcat (lambda (s) (string-append "\"" s "\"")) (cdr (assq 'desc r)) ", "))))) ns)) (define (iter-nodes k) (let lp ((nodes nodes)) (unless (null? nodes) (k (car nodes)) (lp (cdr nodes))))) (define (filter-nodes p) (let ((ns '())) (iter-nodes (fif p (cut find-relation <> (lambda (n) (set! ns (cons n ns)))))) ns)) (define (from-links) (map car nodes)) (define (to-links) (map cdr nodes)) (define (all-members) (delete-duplicates! (from-links))) (define (all-pairs) nodes) (define (ordered-pairs) (concat! (map (lambda (x) (map car (sort (filter-nodes (cute to? <> (car x))) (lambda (x y) (> (get-score x) (get-score y)))))) (sort-nodes (map (lambda (x) (cons x (score-loved x))) (all-members)))))) (define (all-combinations) (let lp ((cs '()) (ns nodes)) (if (null? ns) cs (let ((n (car ns))) (lp (if (member (list (cdr n) (car n)) cs) cs (cons (list (car n) (cdr n)) cs)) (cdr ns)))))) ;; number-list :: [a] -> [(a . Int)] (define (number-list ls) (let lp ((ns '()) (ls ls)) (if (null? ls) ns (let ((x (car ls))) (lp ((fif not (lambda (_) (cons (cons x 1) ns)) (lambda (n) (set-cdr! n (add1 (cdr n))) ns)) (assq x ns)) (cdr ls)))))) ;; sort-nodes :: [(a . Int)] -> [(a . Int)] (define (sort-nodes ns) (sort ns (lambda (x y) (> (cdr x) (cdr y))))) (define (diff-nodes ms ns) (let lp ((ds '()) (ns ns)) (if (null? ns) (sort-nodes ds) (lp (let* ((n (car ns)) (m (assq (car n) ms))) (cons (cons (car n) (- (cdr m) (cdr n))) ds)) (cdr ns))))) (define (get-total-score x p) (foldr (lambda (n acc) (+ (get-score n) acc)) 0 (filter-nodes (cut p <> x)))) (define (score-loved x) (get-total-score x to?)) (define (score-loving x) (get-total-score x from?)) (define (score-between x y) (+ (score-relation (cons x y)) (score-relation (cons y x)))) (define (-> x) (display (format "~%Links from [~a]~%" x)) (iter-nodes (fif (cut from? <> x) print-node))) (define (<- x) (display (format "~%Links towards [~a]~%" x)) (iter-nodes (fif (cut to? <> x) print-node))) (define (<-> x) (display (format "~%Reciprocal links for [~a]~%" x)) (iter-nodes (fif (cut to? <> x) (lambda (n) (flip-relation n (lambda (m) (print-node m n))))))) (define (<=> x) (display (format "~%Reciprocal matches for [~a]~%" x)) (iter-nodes (fif (cut to? <> x) (lambda (n) (flip-relation n (lambda (m) (if (ormap (lambda (x) (ormap (lambda (y) (equal? x y)) (describe-relation m))) (describe-relation n)) (print-node m n)))))))) (define (<?> x) (let ((to (assq x (number-list (from-links)))) (from (assq x (number-list (to-links))))) (display (string-append (format "~%Link statistics for [~a]~%" x) (format "| ~a => ~a (love ~a)~%" x (cdr to) (score-loving x)) (format "| ~a => ~a (love ~a)~%" (cdr from) x (score-loved x)))))) (define (info x) (for-each (cut <> x) (list <- <-> <=> -> <?>))) ;;; GraphViz (http://www.graphviz.org/) support (define graphviz "C:/Program Files/ATT/Graphviz/bin/dot.exe") (define (nodes->dot ns) (string-append "digraph cute {\n" ;;"\tordering=out;\n" ;;"\trankdir=LR;\n" "\toverlap=true;\n" "\tnode[fontname=\"msgothic.ttc\"];\n" "\tedge[fontname=\"msgothic.ttc\",fontsize=9];\n" (let lp ((str "") (ns ns)) (if (null? ns) str (let* ((n (car ns)) (s (score-relation n))) (lp (string-append str (format "\t\"~a\" -> \"~a\"" (symbol->name (car n)) (symbol->name (cdr n))) (format "[label=\"~a\",color=\"~a\"," (break-string (car (describe-relation n)) 7) (cond ((> s 0) "red") ((= s 0) "green") (else "blue"))) (format "style=\"bold~a\"];\n" (if (and (not (= s 0)) (< s 1) (> s -1)) ",dashed" ""))) (cdr ns))))) "}")) (define (write-dotfile dot file) (and (file-exists? file) (delete-file file)) (with-output-to-file file (lambda () (display dot))) file) (define (dot->png dot png) (call-with-input-file (write-dotfile dot "c-ute.dot") (lambda (in) (and (file-exists? png) (delete-file png)) (call-with-output-file png (lambda (out) (run graphviz "-Tpng" in out))))) 'done) ;;; Setup database ;; Based on: ;; http://ex23.2ch.net/test/read.cgi/morningcoffee/1188654905/116-142 (begin (relate 'maimi 'erika "大好き" 1) (relate 'maimi 'kanna "良き妹" 1) (relate 'maimi 'airi "良き妹" 1) (relate 'maimi 'mai "姉妹" 0) (relate 'erika 'maimi "一番可愛いよ" 1) (relate 'erika 'kanna "仲間" 0) (relate 'erika 'chisato "おソロパジャマ" 0) (relate 'kanna 'erika "仲間" 0) (relate 'kanna 'maimi "好き" 1) (relate 'kanna 'saki "喰ってやるよ" 1) (relate 'kanna 'mai "喰ってやるよ" 1) (relate 'kanna 'airi "大好き" 1) (relate 'kanna 'chisato "愛理に手出すんじゃねぇよ" -1) (relate 'saki 'maimi "荷物整理" 0) (relate 'saki 'erika "彼氏にしたい" 1) (relate 'saki 'kanna "興味がある" 0.5) (relate 'saki 'chisato "愛理に手出すんじゃねぇよ" -1) (relate 'saki 'airi "好き" 1) (relate 'airi 'kanna "受け入れる" 1) (relate 'airi 'chisato "最近親密" 1) (relate 'mai 'erika "保護者" 0) (relate 'mai 'maimi "姉妹" 0) (relate 'mai 'chisato "恋人" 1) (relate 'chisato 'erika "おソロパジャマ" 0) (relate 'chisato 'mai "恋人" 1) (relate 'chisato 'airi "最近親密" 1)) ;; query relations / draw graphs (if (file-exists? graphviz) (dot->png (nodes->dot (ordered-pairs)) "c-ute.png") (for-each info (all-members)))
Graphviz というソフトによって関係図を可視化できる、ということを教えていただきました(既に上プログラムを実行すると自動的に関係図画像を作成するようにしてあります)。ここでは技術的な観点から幾つか注意点を挙げておきます。
まず、Scheme プログラムから Graphviz を動かす方法について。コマンドラインからの起動のように、プログラムへのオプション文字列で入出力ファイルを指定する方法ではどうも上手く行きませんでした。調査の結果、入出力ファイルのポートを Scheme 側で用意しておく必要があるようです。処理系によって異なりますが、PLT Scheme の場合 subprocess という関数を次のように呼び出します。
(subprocess output-port input-port #f "/path/to/dot.exe" "-Tpng")
ここで output-port は png 等画像ファイルへの出力ポート。input-port は dot ファイル(グラフの定義ファイル)の入力ポートです。エラーポートは必要無いでしょう (#f)。
dot という名前の実行ファイルが、関係図のような有向グラフを描画するプログラムです。最後にオプション文字列として出力形式を指定します(png, jpeg, gif, etc.)。
次に dot ファイルを Scheme で書く方法ですが、以下の基本的な有向グラフの書式
digraph g { A -> B; B -> C; C -> A; }
を理解すれば、後は実直に Scheme のデータを当てはめて format 関数等で変換するだけです。
(string-append "digraph g {" (format "~a -> ~a;" (car node) (cdr node)) "}")
問題は、ノードを配置する順番によって出来上がる画像が変わってくる、ということです。
より見た目に分かりやすくするための工夫としては、相互にリンクするノード同士が dot ファイル上でも近接して出力されるようにすると良いでしょう。関連の強いものが画像の上でも近くに表示されるようになります。
また上述(特に例3)のスコアの概念を応用し、スコアの低いものが後に出力されるようにすることで、重力感覚に一致するような関係図を得ることができるでしょう。
マルコが知ってるのはEQだけだから違う