Hatena::Groupcadr

わだばLisperになる このページをアンテナに追加 RSSフィード

2004 | 12 |
2005 | 01 | 02 | 07 | 10 | 11 |
2006 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2007 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2008 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2009 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2010 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2011 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 11 |

2007-11-03

Series (2)

| 22:48 |  Series (2) - わだばLisperになる を含むブックマーク はてなブックマーク -  Series (2) - わだばLisperになる

今回もSeriesがどんなものなのか色々試してみています。

実際の利用事例をGoogle Codeを使って検索してみるのですが、利用例は見当らずで、見付かるものといえばSERIES自体のソースコード位です。

CLTL2では、map-fnを#M、seriesを#Zとリードマクロ文字で定義して表記してあります。

これは、表記としても使う上でも便利だなと思うのですが、自分で定義しないといけないんだと思ってコードを検索してみたら、SERIESのソース自体に定義がありました(*'-')

(series::install)

を実行することで使えるようになるらしいです。が、#Mが自分の手元だと上手く機能しません…。何が間違っているのだろうか…。

色々試してみる

自分の予想では、SERIESはSRFI-42に非常に近い使い勝手ではないだろうか思い、SRFI-42の使用例をSERIESに翻訳してみることにしました。ちなみに自分は、SRFI-42の使い方も良く分かっているわけではありません…。

とりあえずウェブで見付けてきた題材と翻訳を列記してみます。

doukaku.org:九九の表示よりdo-ecの例
;; doukaku 
(define (display99 n)
  (do-ec (: x 1 (+ n 1)) (: y 1 (+ n 1))
         (format #t "~d * ~d = ~2d~%" x y (* x y))))
;; SERIESで
(defun display99 (n)
  (iterate ((x (scan-range :from 1 :upto n)))
    (iterate ((y (scan-range :from 1 :upto n)))
      (format t "~D * ~D = ~2D~%" x y (* x y)))))

適当なマクロですが、

(defmacro iterate* (binds &body body)
  `,(reduce (lambda (b res)
	      `(iterate (,b) ,res))
	    binds
	    :initial-value `(progn ,@body)
	    :from-end 'T))

のようにすれば、

(defun display99 (n)
  (iterate* ((x (scan-range :from 1 :upto n)) 
             (y (scan-range :from 1 :upto n)))
    (format t "~D * ~D = ~2D~%" x y (* x y))))

と書けてより近いような気もしましたが、気休めな気もします。

上記を任意の数に拡張した版
(define (displayNN n)
  (let ((w0 (string-length (number->string n)))
        (w1 (string-length (number->string (* n n)))))
    (do-ec (: x 1 (+ n 1)) (: y 1 (+ n 1))
           (format #t "~vd * ~vd = ~vd~%" w0 x w0 y w1 (* x y)))))
;; SERIESで
(defun displayNN (n)
  (let ((w0 (length (princ-to-string n)))
	(w1 (length (princ-to-string (* n n)))))
    (iterate ((x (scan-range :from 1 :upto n)))
      (iterate ((y (scan-range :from 1 :upto n)))
	(format t "~VD * ~VD = ~VD~%" w0 x w0 y w1 (* x y))))))
doukaku.org:隣り合う二項の差よりlist-ecの例
(define (diff xs) (list-ec (:parallel (: x xs) (: y (cdr xs))) (- y x)))
;; SERIESで
(defun diff (xs) 
  (collect (mapping ((x (scan xs)) (y (scan (cdr xs)))) (- y x))))
;;
(diff '(2 1 4 3 6 5 7))
;-> (-1 3 -1 3 -1 2)

SRFI-42ではデフォルトで入れ子になり:parallelを指定することにより並列になるそうですが、SERIESはデフォルトが並列で、入れ子は手作りになります。

doukaku.org:ダブル完全数よりsum-ecの例
(define (double-complete-number? n)
  (= (* n 3)
     (sum-ec (: i 1 (+ 1 n))
             (if (zero? (remainder n i)))
             i)))

(do-ec (: i 1 10001)
       (if (double-complete-number? i) (print i)))
;; SERIESで
(defun double-complete-number-p (n)
  (= (* n 3)
     (collect-sum 
      (choose
       (mapping ((i (scan-range :from 1 :upto n)))
	 (when (zerop (rem n i)) i))))))

(iterate ((i (scan-range :from 1 :upto 10000)))
  (when (double-complete-number-p i)
    (print i)))

まとめ

というようにSRFI-42をSERIESに変換してみましたが、結構何の捻りもなしに素直に変換できるようです。関数/マクロの名前の付け方にも非常に共通点が多いというのも理由の一つかもしれません。

ゲスト



トラックバック - http://cadr.g.hatena.ne.jp/g000001/20071103