「Schemerの常識は他のプログラマの非常識」という理念に基づき、 実際のプログラムによく出てくる定型を列挙するコーナー。
といいつつ実際なんの役に立つのかわからないけどとりあえずおもしろいから いいやとか、単に笑えるだけの技なんかも集まるといいなあ。 大きいものは別に項目を立てるとして、こっちは10行くらいをメドに。
モデルにしたのはこのへん。
http://www.asahi-net.or.jp/~dp8t-asm/java/idiom/index.html
当面整理しないでただ並べておく。
(values)
(if #f #f)
(read-from-string "")
(if expr #t #f) ;#fが省略できないことに注意! or (and expr #t) or (not (not expr))
[Guileには->boolという関数が用意されている]
(string-append str1 str2) or (use srfi-13) (string-concatenate (list str1 str2)) or #`",|str1|,|str2|" or (format "~a~a" str1 str2) or (with-output-to-string (lambda () (display str1) (display str2)))
(dotimes (i 10) (print i)) or (use srfi-1) (for-each print (iota 10))
(filter values (map proc xs))
or
(use srfi-1) (filter-map proc xs)
(cut proc arg)
例:
(call-with-input-file f (lambda (port) (port-map fn (cut read-line port))))
(with-error-handler (lambda (e) (close-output-port port) (raise e)) (lambda () (begin0 (proc port) (close-output-port port))))
これは次のようにも書ける。上のコードに展開される。GaucheRefj:unwind-protect
(unwind-protect (proc port) (close-output-port port))
call/cc を使って proc の dynamic extent に出入りしない場合は以下も同じだけど、 call/ccが使われるかどうかは一般には知り得ない(procから呼んでるライブラリの 中で使われるかもしれない)ので、こういう目的でdynamic-windを使うことは あまりお薦めしない。
(dynamic-wind (cut values #f) (cut proc port) (cut close-output-port port))
(define func1 #f) (define func2 #f) (let ((shared 1) (variable 2)) (set! func1 (lambda () ...)) (set! func2 (lambda () ...)))
or
(define-values (func1 func2) (let ((shared 1) (variable 2)) (values (lambda () ...) (lambda () ...))))
define-values (var ...) expr なので、internal define は直接つかえない。
(define-values (func1 func2) (define shared 1) (define variable 2) (values (lambda () ...) (lambda () ...))) ; => *** ERROR: Compile Error: malformed define-values ...
let をはさめば大丈夫。
(define-values (func1 func2) (let () (define shared 1) (define variable 2) (values (lambda () ...) (lambda () ...))))
(cond ((assoc key alist) => cdr) (else #f))
or
(and-let* ((pair (assoc key alist))) (cdr pair))
or
(use util.list) (assoc-ref alist key)