ACL 4章

ANSI Common Lisp読み。


練習問題が変態過ぎ。

長年にわたる議論の末、ある政府委員会が次のように決定した。リストは第一要素を示すために、cdrを使い、その残りを示すためにcarを用いなければならない。この方針にしたがって、以下の関数を定義せよ。

cons,list,length,member

どんな政府委員会だよ。


回答例を見ながら答え合わせしてみると、破壊的にやっちゃった方が効率の良いものが多い。


P.Graham 著 ANSI Common LISP 練習問題解答


例えば、mapを使って、要素に位置を示す数を加える問題。

(pos+ '(7 5 1 4)) ; (7 6 3 7)

length取って、iotaして2個のリストでmapとか書いてたけど、全然効率が悪い。

set!を使ってインデックスを加えたほうがいい。なるほど。


まだ「最長」経路問題が残ってるので、ちまちま考えてみる。


出来た。

  • 検索が完了した経路をどんどん除いていく。
  • 循環チェックは(A B C)とあって、同じのがあったら循環してることがわかる。
  • 最後まで残る経路が最長なので、経路が無くなったら、最後の経路を返す。
(define (longest-path start net)
  (letrec
    ((bfs (lambda (queue acc)
            (if (null? queue)
                (reverse (car acc))
                (let* ((path (car queue))
                       (node (car path))
                       (new (new-paths path node)))
                      (cond ((null? new)
                             (bfs (cdr queue) (cons path acc))) ; 新たな経路がない
                            ((member node (cdr path))
                             (bfs (cdr queue) (cons (cdr path) acc))) ; 循環してた
                            (else
                              (bfs (append (cdr queue) new) acc))))))) ; まだまだ
     (new-paths (lambda (path node)
                  (let ((finds (assoc node net)))
                       (if finds
                           (map (lambda (n)
                                  (cons n path))
                                (cdr finds))
                           '())))))
    (bfs (list (list start)) '())))

(longest-path 'A '((A B) (B C D) (C A D) (D E))) ; (A B C D E)

新たな経路が無いことを確認するのに手間取った。


まとめ。

  • ノードの終了は、新たな経路が見つからないか、循環してるかを調べればわかる。
  • 最長を求めるなんて無理じゃねと思ってたけど、循環を除けば最長もわかる。

勉強になった。