よっしゃ! レベル4や!

どもです。
朝起きて,飯喰って,昨日の計算の続きというか,
一般項を全部求めなくてもいけるんじゃね? ということを確認したら,
やはり求める必要はなさそうだ。


なんの話かというと,Project Euler の Problem 101 のことね。
ほいで,これに正解して,めでたく100問解いたので(途中1問飛ばしている。モノポリーの話のやつ),
レベル4にあがったのです。
その記念にコードを晒そうず。
というか,結構学習になったので,その備忘録ということで。


next-seq-term という関数を書いたところで挙動を確認したのですが,
おかしい。
トレースしようと思って,C-cC-t してトレースオンしても,
最適化されているせいか? 肝心の再帰部分を見せてくれない。
というか,再帰すらしてないのかもしれんが。
んで,ぐぐったりして,わかった。
敬遠していた,declare とかでした。んで,(debug 3) すると再帰部分を見せてくれました。
挙動がおかしかった原因は,関数名を変更して修正したが,
再帰部分の関数名を変更してなかったというオチ。


それから,loop マクロでリストの部分リストについてループしたい場合は,
(loop for var on lst ...) とか使うというということを初めて知った。
オンですよ,オン。
参考: http://www.gigamonkeys.com/book/loop-for-black-belts.html


で,デフォルトだとループ毎に cdr ってくようです。
しかし,今回はそれだと都合が悪いので,えいやと,butlast を入れてみたら
期待通りの動きをしてくれた。
こういうことね。

CL-USER> (loop for x on '(1 2 3 4) by #'butlast collect x)
((1 2 3 4) (1 2 3) (1 2) (1))


んで,そのコード。解答をさらすのは気が引けるが,記念じゃ,記念。
ま,何回か書いているけど,最初は,全部の階差数列について,
手で一般項を求めてようという,オレの能力に比して無謀なことをやろうとしていたのです。
あきらめたけど。n^4 の和とかしらんし。ん? 和ちゃんがこんなところにっ!!

;; problem 101
(defun u-n (n)
  (- (+ 1 (expt n 2) (expt n 4) (expt n 6) (expt n 8) (expt n 10))
     (+ n (expt n 3) (expt n 5) (expt n 7) (expt n 9))))

(loop for n from 1 to 10
               collect (u-n n))
;; => (1 683 44287 838861 8138021 51828151 247165843 954437177 3138105961 9090909091)

(defun next-seq-term (seq)
  ;;(declare (optimize (debug 3)))
  (if (= 1 (length seq))
      (car seq)
      (+ (car (last seq))
         (next-seq-term (mapcar #'- (cdr seq) seq)))))

(defun solve-e101 ()
  (loop for seq on (loop for i from 1 to 10 collect (u-n i)) by #'butlast
        summing (next-seq-term seq)))

今思ったが,(if (= 1 (length seq))) の部分は,(if (null (cdr seq))) の方がよいかも?
ま,大した長さではないから,今回は問題にならんかね。
そんな感じです。おつです。
さて,フォーラムを覗きに行ってきます。これが勉強になるんすわ。