読者です 読者をやめる 読者になる 読者になる

続・compact-number-list他

畳み込みを使ったコードが出てきてたのを見て、CLで書いてみた。

(defun compact-number-list (x)
  (reduce
   #'(lambda(n r)
       (let ((c (car r)))
         (if (eql (1+ n) (or (safe-car c) c))
             `((,n .,(or (safe-cdr c) c)) ,@(cdr r))
             `(,n ,@r))))
   `(,@x nil) :from-end t))

ほぼirieさんのコードのコピペ。

もう1つ、scinfaxiさんの回答のfold2が気になったので調べてみる。
Gauche ユーザリファレンス: 8.2 ライブラリの命名規則
へーへーへー。面白い。
CLで書くとこんな感じ?

(defun fold2 (proc knil1 knil2 &rest lists)
  (if (some #'null lists)
      (values knil1 knil2)
      (multiple-value-bind (n1 n2)
          (apply proc `(,@(mapcar #'car lists) ,knil1 ,knil2))
        (apply #'fold2 proc n1 n2 (mapcar #'cdr lists)))))

(defun compact-number-list (r)
  (reverse
   (fold2
    (lambda (c r p)
      (values
       (if (= c (+ p 1))
           r
           (list* c (if (= #0=(car r) p) p (cons #0# p)) #1=(cdr r)))
       c))
    `(,#0#) #0# #1#)))

(compact-number-list '(1 3 4 5 7 8 9 12 13))
; => (1 (3 . 5) (7 . 9) 12)

ちゃんと動いた。

ついでに、#?=も気になったので調べてみる。
Gauche ユーザリファレンス: 3.4 デバッグ
便利そう。簡単なものを書いてみよう。

(defmacro debug-print (form)
  (let ((v (gensym)))
    `(progn
       (format t "~&#?= ~S~%" ',form)
       (let ((,v ,form))
         (format t "~&#?-     ~A" ,v)
         ,v))))

(set-dispatch-macro-character #\# #\?
  #'(lambda (s c1 c2)
      (declare (ignore c1 c2))
      (read-char s)
      `(debug-print ,(read s))))

実行

CL-USER> (defun fact (n)
  (if (= n 0) 1
      (* n #?=(fact (1- n)))))
FACT
CL-USER> (fact 5)
#?= (FACT (1- N))
#?= (FACT (1- N))
#?= (FACT (1- N))
#?= (FACT (1- N))
#?= (FACT (1- N))
#?-     1
#?-     1
#?-     2
#?-     6
#?-     24
120

とりあえずこれは動いたけど、リーダーの書き方がダメらしく

(list (debug-print (list #1=1 2 3)) #1#)

は大丈夫だけど

(list #?=(list #1=1 2 3) #1#)

はラベルが無い、と怒られる。

改善策が分からないのでまた今度。