順列に対する手続き

組み合わせパズルなんかを解くときに楽。かも

permutations-any,permutations*-anyutil.combinationsに追加って感じで*1

(define (but-kth lis k)
  (receive (head tail) (split-at lis k)
    (append! head (cdr tail))))

(define (any-with-index pred lis1 . lists)
  (let1 index -1
    (apply any
           (lambda (item1 . items)
             (apply pred `(,(inc! index) ,item1 . ,items)))
           lis1 lists)))

(define (permutations-any pred set)
  (cond ((null? set) (pred set))
        ((null? (cdr set)) (pred set))
        (else
          (any-with-index
            (lambda (ind elt)
              (permutations-any
                (lambda (subperm) (pred (cons elt subperm)))
                (but-kth set ind)))
            set))))

(define (permutations*-any pred set . maybe-eq)
  (cond
    ((null? set) (pred set))
    ((null? (cdr set)) (pred set))
    (else
      (let1 eq (get-optional maybe-eq eqv?)
        (let loop ((i 0) (seen '()) (p set))
          (cond
            ((null? p) #f)
            ((member (car p) seen eq) (loop (+ i 1) seen (cdr p)))
            (else
              (or (permutations*-any
                    (lambda (subperm) (pred (cons (car p) subperm))) (but-kth set i) eq)
                  (loop (+ i 1) (cons (car p) seen) (cdr p))))))))))

まーちゃんと動くかどうかは検証してないんだけれども。

(permutations-any (pa$ apply >) '(10 9 8 7 6 5 4 3 2 1))

はすぐに#tを返すけど、

(any (pa$ apply >) (permutations '(10 9 8 7 6 5 4 3 2 1)))

はまず10!個のリストを生成するんで終わんない。

-everyも作れよ!ってな!

*1:てかソースがモロパクり