Code Aquarium

minazoko's blog -*- 水底のブログ -*-

(Racket) Class の External Name Control

RacketのClassシステムの説明にある Internal / External Names がピンと来なかったので、サンプルを書いてみました。
公式ドキュメントでは 比較対象にJavaのprotectedを例にあげていますが、むしろ C++ の friend に近いような気がします。

Racketのdefine-member-nameの例(gist)

generate-member-key はgensymで内部シンボルを作っています。define-member-name で束縛すると、束縛されたシンボルと同名のメソッドが外部から参照できなくなる仕組みです。

(Racket) generatorでFizzBuzz

racketにもgeneratorライブラリがあるので、前回のgaucheのコードを移植……しようとした。しかしracketのgeneratorは汎用ストリームのように使うには、どうにも使いづらかった……。
steramとの相互変換が出来ればもっと楽できそうなんだけど。

#lang racket

(require racket/generator)
(require srfi/1)

(define (circular n s)
  (sequence->repeated-generator
   (cons s (make-list (- n 1) ""))))

(define (giota)
  (infinite-generator
   (let loop ((n 0))
     (yield n)
     (loop (+ n 1)))))

(define (generator->list g n)
  (unfold (λ(a)(zero? (cdr a)))
          (λ(a)((car a)))
          (λ(a)(cons (car a) (- (cdr a) 1)))
          (cons g n)))

(define (gfizzbuzz)
  (let ((g (infinite-generator
            (let loop ((gens (list (giota)
                                   (circular 3 "Fizz")
                                   (circular 5 "Buzz"))))
              (yield (match (map (λ(g)(g)) gens)
                       ((list n "" "") n)
                       ((list _ f b) (string-append f b))))
              (loop gens)))))
    (g)  ; drop 1
    g))


;; usage example
;; (generator->list (gfizzbuzz) 100)

追記 (2014/10/7)

for系syntaxや、シーケンスライブラリ in-xxx を使うともう少し綺麗に書けそう。

#lang racket
(require racket/generator)

(define (circular n s)
  (sequence->repeated-generator
   (cons s (make-list (- n 1) ""))))

(define (generator->list g n)
  (for/list ((i (in-naturals)) #:break (>= i n))
    (g)))

(define (gfizzbuzz)
  (define gens (list (circular 3 "Fizz")
                     (circular 5 "Buzz")))
  (let ((g (generator ()
            (for ((i (in-naturals)))
              (yield (match (map (λ(g)(g)) gens)
                       ((list "" "") i)
                       ((list f "") f)
                       ((list "" b) b)
                       ((list f b) (string-append f b))))))))
    (g)  ; drop 1
    g))

(generator->list (gfizzbuzz) 100)

ClojureのスレッドマクロをSchemeで

Clojureのマクロ -> と ->> のScheme版です。動作確認はRacketでしましたが、syntax-rulesしか使ってないので他の処理系でも動くかな?

apply->とapply->>は補助用のヘルパマクロです。似たような構造が並んでいるので共通部分を共通化することも考えましたが、この程度だとむしろベタに並べた方が分かりやすいのかなと思ってこうなりました。

 Schemeではnumber->stringやstring->listのようにデータ変換の意味で->を使うので、意味の異なる用途である上記のマクロにこういう名前を付けるのは好ましくない気がしますね。Clojureを知ってる人に見せる分には問題ないのですが。