#:g1: srfi 86の紹介

Posted 2014-11-21 15:00:00 GMT

(LISP Library 365参加エントリ)

 LISP Library 365 の326日目です。

srfi 86とはなにか

 srfi 86は、Joo ChurlSoo氏による究極の束縛構文の提案です。

パッケージ情報

パッケージ名srfi 86
SRFISRFI 86: MU and NU simulating VALUES & CALL-WITH-VALUES, and their related LET-syntax

インストール方法

 SagittariusとRacketでは標準で使えます。

;;; Sagittarius
(import (srfi 86))

;;; Racket (require srfi/86)

試してみる

の記事の使い回しなのですが、コード例をSchemeで動くように書き換えるとこんな感じになります。

多値 & 分配束縛

 muが多値でnuがリストという感じです。

(alet (a (mu 1 2)
        ((b c) (mu 3 4)))
  (list a b c))
;=> ((1 2) 3 4)

(alet (((a . b) (nu '(1 2 3 4)))) (list a b)) ;=> (1 (2 3 4))

(alet (((values a b) (values 3 4))) (list a b)) ;=> (3 4)

名前付きLET

 ノーマルなnamed-letの形式に加え、束縛部のリストの終端に名前を持ってくるという斬新な手法により複数の関数を扱えるようにしてあります。さらに謎のネストも可能

(alet* tag ((a 1)
            (a b b c (mu (+ a 2) 4 5 6))
            ((d e e) b 5 (+ a b c)))
  (if (< a 10)
      (tag a 10 b c c d e d)
      (list a b c d e)))
;=> (10 6 6 5 5)

(alet fact ((n 10) (a 1))
  (if (zero? n)
      a
      (fact (- n 1) (* a n))))
;=> 3628800

;; 名前が後ろにある形式の名前付きLET

(alet (((n 10) (a 1) . fact))
      (if (zero? n)
          a
          (fact (- n 1) (* a n))))
;=> 3628800

;; intagとtagで入れ子
(alet* ((a 1)
        ((b 2)
         (b c c (mu 3 4 5))
         ((d e d (mu a b c)) . intag)
         . tag)
        (f 6))
  (if (< d 10)
      (intag d e 10)
      (if (< c 10)
          (tag b 11 c 12 a b d intag)
          (list a b c d e f))))
;=> (1 11 12 10 3 6)

継続関係

 call/ccの糖衣構文であるlet/cc的なものもサポート。

; 脱出(継続)
(alet lp ((win)
          (list '(1 2 3 4 5 6 7)))
  (cond ((= 3 (car list))
         (win (car list)))
        (else (print (car list))
              (lp win (cdr list)))))
;->
;   1
;   2
;=> 3

and-let*

 and-let*も貪欲に取り込み

;; and-let*
(alet* ((alist '((a . 1) (b . 2) (c . 3)))
        (and (a (assoc 'b alist))))
  (cdr a))
;=> 2

Common Lispのlambda-list的なものをサポート

 Common Lispでいう&rest、&optional、&keyを越えるものをサポート。キーワードのキーとして文字列も使えます。

;; キーワードで分配
(alet ((key '(b 20 a 10 c 30)
            (a :init)
            (b :init)
            (c :init)
            (d :init)))
  (list a b c d))
;=> (10 20 30 :init)

;; Common Lispのdestructuring-bindとの比較 (destructuring-bind (&key ((a a) :init) ((b b) :init) ((c c) :init) ((d d) :init)) '(b 20 a 10 c 30) (list a b c d)) ;=> (10 20 30 :INIT)

;; もっとエグい (alet ((key '(:a 10 :cc 30 40 b 20) ((a :a) 1) ((b :b) 2) ((c :cc) 3) . d)) (list a b c d)) ;=> (10 2 30 (40 b 20))

;; 文字もキーにできる (alet ((key '("a" 10 "cc" 30 40 b 20) ((a "a") 1) ((b "b") 2) ((c "cc") 3) . d)) (list a b c d)) ;=> (10 2 30 (40 B 20))

letrec系

 letrec形式も勿論サポート

(alet ((rec (fact (lambda (n)
                    (if (zero? n)
                        1
                        (* n (fact (- n 1))))))))
  (fact 10))
;=> 3628800

その他

(let ((a #f) (b #f))
  (alet ((a :a)
         (b :b)
         (() (set! a 100)
             (set! b 200)))
    (list a b)))
;=> (:a :b)
(let (a b) (set! a 100) (set! b 200)
        (alet ((a :a) (b :b))
              (list a b)))
;=> (:a :b)

(let ((a #f) (b #f))
  (alet* ((a :a)
          (b :b)
          (() (set! a 100)
              (set! b 200)))
    (list a b)))
;=> (100 200)
(let (a b)
     (alet* ((a :a) (b :b))
            (set! a 100)
            (set! b 200)
            (list a b)))
;=> (100 200)

(alet ((cat '(1 -2 3) (a 0 (positive? a)) (b 0 (positive? b)) (c 0 (positive? c)) . d)) (list a b c d)) ;=> (1 3 0 (-2))

色々複合した例

(let ((m #f) (n #f))
  (alet* ((a (begin (display "1st") 1))
          ((b c) 2 (begin (display "2nd") 3))
          (() (set! m #f) (set! n (list 8)))
          ((d (begin (display "3rd") 4))
           (key '(e 5 tmp 6) (e 0) ((f 'tmp) 55)) . p)
          g (nu (begin (display "4th") 7) n)
          ((values . h) (apply values 7 (begin (display "5th") n)))
          ((m 11) (n n) . q)
          (rec (i (lambda () (- (j) 1)))
               (j (lambda ()  10)))
          (and (k (begin (display "6th") m))
               (l (begin (display "end") (newline) 12)))
          (o))
    (if (< d 10)
        (p 40 50 60)
        (if (< m 100)
            (q 111 n)
            (begin (display (list a b c d e f g h
                                  (i)
                                  (j)
                                k l m n))
                   (newline))))
    (o (list 'o p q))
    (display "This is not displayed")))
;-> 1st2nd3rd4th5th6thend
;-> 4th5th6thend
;-> 6thend
;-> (1 2 3 40 50 60 (7 8) (7 8) 9 10 111 12 111 (8))
;=> (o #<closure #<identifier p#user>> #<closure #<identifier q#user>>)

まとめ

 今回は、srfi 86を紹介してみました。
Joo ChurlSoo氏のSRFIは面白いものが多いのですが、紹介するのもなかなか大変です。

comments powered by Disqus