2.2.3 Sequences as Conventional Interfaces

だんだん問題解くのが面倒になってきた。

前準備

(define (accumulate op initial sequence)
  (if (null? sequence)
      initial
      (op (car sequence)
          (accumulate op initial (cdr sequence)))))

2.33 (リストの基本関数をaccumulateで書き換え)

(define (%map p sequence)
  (accumulate (lambda (x y) (cons (p x) y)) '() sequence))

(define (%append seq1 seq2)
  (accumulate cons seq2 seq1))

(define (%length sequence)
  (accumulate (lambda (_ l) (+ l 1)) 0 sequence))

2.34 (Horner法)

(define (horner-eval x coefficient-sequence)
  (accumulate (lambda (this-coeff higher-terms)
                (+ (* higher-terms x) this-coeff))
              0
              coefficient-sequence))

2.35 (count-leaves, accumulate版)

(define (count-leaves t)
  (accumulate +
              0
              (map
                (lambda (t)
                  (if (pair? t)
                    (+ (count-leaves (list (car t)))
                       (count-leaves (cdr t)))
                    1))
                t)))

2.36 (複数のリストを取るaccumulate-n)

(define (accumulate-n op init seqs)
  (if (null? (car seqs))
    '()
    (cons (accumulate op init (map car seqs))
          (accumulate-n op init (map cdr seqs)))))
(accumulate-n + 0 '((1 2 3) (4 5 6) (7 8 9) (10 11 12)))

2.37 (行列・ベクトルの演算)

(define (dot-product v w)
  (accumulate + 0 (map * v w)))

(define (matrix-*-vector m v)
  (map (lambda (r) (dot-product r v)) m))

(define (transpose m)
  (accumulate-n cons '() m))
(accumulate-n * 1 '((1 2 3) (4 5 6)))

(define (matrix-*-matrix m n)
  (let ((cols (transpose n)))
    (map (lambda (row)
           (map (lambda (col) (accumulate + 0 (map * row col))) cols))
         m)))

2.38 (fold-left, fold-right)

省略。

;(fold cons '() (list 1 2 3 4 5))
; => (5 4 3 2 1)
;(fold-right cons '() (list 1 2 3 4 5))
; => (1 2 3 4 5)

となることを覚えておくと混乱しないかも。

2.39

(define (reverse sequence)
  (fold-right (lambda (x y) (append y (list x))) '() sequence))

(define (reverse sequence)
  (fold-left (lambda (x y) (cons x y)) '() sequence))

2.40

(define (enumerate-interval low high)
  (if (> low high)
    '()
    (cons low (enumerate-interval (+ low 1) high))))

(define (flatmap proc seq)
    (accumulate append '() (map proc seq)))

(define (unique-pairs n)
  (flatmap
    (lambda (i)
      (map
        (lambda (j)
          (list i j))
        (enumerate-interval 1 (- i 1))))
    (enumerate-interval 1 n)))

(define (prime-sum-pairs n)
  (map make-pair-sum
       (filter prime-sum? (unique-pairs n))))

flatmapというのはSRFI-1のappend-map.

2.41

(define (filter predicate sequence)
  (cond ((null? sequence) '())
        ((predicate (car sequence))
         (cons (car sequence)
               (filter predicate (cdr sequence))))
        (else (filter predicate (cdr sequence)))))

(define (ordered-triples-of-sum<= n)
  (filter (lambda (triple)
            (<= (accumulate + 0 triple) n))
          (flatmap
            (lambda (i)
              (flatmap
                (lambda (j)
                  (map
                    (lambda (k)
                      (list i j k))
                    (enumerate-interval (+ j 1) n)))
                (enumerate-interval (+ i 1) n)))
            (enumerate-interval 1 n))
          ))

2.42 (8-queens puzzle)

やる気がなくなったので以前読んだときにやっていたのでそれを。Gauche

;; Exercise 2.42
;; Eight-queens puzzle

(use srfi-1)

(define empty-board '())

(define (queens board-size)
  (define (queen-cols k)
    (if (= k 0)
      (list empty-board)
      (filter
        (lambda (positions) (safe? k positions))
        (append-map
          (lambda (rest-of-queens)
            (map (lambda (new-row)
                   (adjoin-position new-row k rest-of-queens))
                 (enumerate-interval 1 board-size)))
          (queen-cols (- k 1))))
      ))
  (queen-cols board-size))

(define (adjoin-position new-row k rest-of-queens)
  (append rest-of-queens (list new-row)))

(define (enumerate-interval interval end)
  (if (<= end 0) '()
    (append (enumerate-interval interval (- end interval)) (list (- end 1)))))

(define (safe? k positions)
  (define (sub-safe? pos positions k)
    (if (null? positions) #t
      (if (= k 0)
        (sub-safe? pos (cdr positions) (- k 1))
        (and (not (= pos (car positions)))
             (sub-safe? pos (cdr positions) (- k 1))))))
  (sub-safe? (list-ref positions (- k 1)) positions (- k 1)))

(define (main args)
  (display (queens 8)))

8 Queens Problem - ミラクル☆モテメンの脱オタ日記というのもあった。

2.43

新しい場所を一つ仮定するたびに、その右側(左側かもしれない)のクイーンの位置を計算しなおしているのでかなり遅くなる。かかる時間は8^8倍より小さいけどこのくらいのオーダかなぁ(自信なし)。