2012年05月20日
■ オリーブハマチ
私は香川県民だ。 さて、香川県というと脊髄反射のようにうどんを連想してしまう人が大半だろう。 県別のうどん消費量の資料を見ると香川県が群を抜いていることからもわかるように、うどんばかり食べている人が多いというのも事実ではある。
とは云っても香川県民ならだれもがうどんを好むかというとそんなことはない。 私は昔からうどんを苦手としている。 というより、普通の感性をもっている人なら香川県でのうどんに関する感覚は本当に常軌を逸っしているとしか思えないだろう。 例えば年越しうどん。 そばのかわりにうどんを食べるというのはそういう風習の地域があるということでわからないこともない。 かと思えば年明けうどん。 お前、さっきもうどん食うとったやろ!! そんなこんなで何か祝い事があればとりあえずうどんという感じは本当に勘弁して欲しい。 っていうか、祝い事のときは普段は食べられないものが出てくるものじゃないのか。 普段からしょっちゅう食ってるものをまた食って嬉しいのかと小一時間問い詰めたい。 そんなわけで香川県といえばうどんという状況を苦々しく思っている。
そこで、別の特産品を紹介する。 その名もオリーブハマチ。 オリーブの葉を餌に混ぜて与えることでその身の臭みを軽減、それどころか風味豊かで普通のハマチと比べると段違いの旨さである。 そもそも日本でオリーブの栽培に成功しているのは瀬戸内の一部のみであり、オリーブも香川県の特産品と言えるだろう。
せっかく最近になってオリーブハマチの生産がある程度軌道に載ってきたというのにうどん中心のイメージ戦略 (というか、実態としてもうどんばかりだが) の影に隠れてしまっているのが残念でならない。 だから私は主張する。 これからの香川県の特産品はオリーブハマチであると。
2012年04月19日
■ デフォルトの評価
Scheme では標準の構文では手続の引数にデフォルト値を設定することは出来ないが Gauche や Chicken Scheme には一部 (又は全て) の引数を渡すことを省略できる仕組が用意されている。 省略した場合には予め指定しておいた式を評価してデフォルト値とするわけだ。
さて、一方で Python では関数の引数のデフォルト値は、関数の定義時に一回しか評価されないという話を小耳に狭んだので、それを Scheme でも実現するマクロを書いてみた。
#!r6rs (library (optional-arguments) (export (rename (opt:define define) (opt:lambda lambda))) (import (rnrs)) (define-syntax let-optionals* (syntax-rules () ((_ a ((v d) . r) b0 b1 ...) (let* ((t a) (v (if (null? t) d (car t)))) (let-optionals* (if (null? t) '() (cdr t)) r b0 b1 ...))) ((_ a () b0 b1 ...) (begin b0 b1 ...)) ((_ a (v . r) b0 b1 ...) (let* ((t a) (v (if (null? t) #f (car t)))) (let-optionals* (if (null? t) '() (cdr t)) r b0 b1 ...))) ((_ a rv b0 b1 ...) (let ((rv a)) b0 b1 ...)))) (define-syntax %%opt:lambda (syntax-rules () ((_ () (f ...) (i ...) (n ...) body ...) (let (i ...) (lambda (f ... . opt) (let-optionals* opt (n ...) body ...)))) ((_ rest (f ...) (i ...) (n ...) body ...) (let (i ...) (lambda (f ... . opt) (let-optionals* opt (n ... . rest) body ...)))))) (define-syntax %opte:lambda (syntax-rules (:opti :opte) ((_ ((var default) . rest) f (i ...) (n ...) body ...) (%opti:lambda rest f (i ...) (n ... (var default)) body ...)) ((_ (:opti . rest) f (i ...) (n ...) body ...) (%opti:lambda rest f (i ...) (n ...) body ...)) ((_ a ...) (%%opt:lambda a ...)))) (define-syntax %opti:lambda (syntax-rules (:opti :opte) ((_ ((var default) . rest) f (i ...) (n ...) body ...) (%opti:lambda rest f (i ... (t default)) (n ... (var t)) body ...)) ((_ (:opte . rest) f (i ...) (n ...) body ...) (%opte:lambda rest f (i ...) (n ...) body ...)) ((_ a ...) (%%opt:lambda a ...)))) (define-syntax %opt:lambda (syntax-rules (:opti :opte) ((_ (:opti . rest) (f ...) body ...) (%opti:lambda rest (f ...) () () body ...)) ((_ (:opte . rest) (f ...) body ...) (%opte:lambda rest (f ...) () () body ...)) ((_ () (f ...) body ...) (lambda (f ...) body ...)) ((_ (arg . rest) (f ...) body ...) (%opt:lambda rest (f ... arg) body ...)) ((_ rest (f ...) body ...) (lambda (f ... . rest) body ...)))) (define-syntax opt:lambda (syntax-rules () ((_ () b0 b1 ...) (lambda() b0 b1 ...)) ((_ args b0 b1 ...) (%opt:lambda args () b0 b1 ...)))) (define-syntax opt:define (syntax-rules () ((_ (name . args) b0 b1 ...) (opt:define name (opt:lambda args b0 b1 ...))) ((_ name obj) (define name obj)))) )
使い方の例は以下のようになる。
#!r6rs (import (except (rnrs) define) (only (optional-arguments) define)) (define (test1) (display "test1\n") 1) (define (test2) (display "test2\n") 2) (display "Start definition\n") (define (hoge :opti (a (test1)) (b (test2)) :opte (c (test2))) (write (list "hoge" a b c)) (newline)) (display "End definition\n") (display "Run\n") (hoge) (display "End\n")
:opti に続く引数はデフォルト引数が定義時に評価され、 :opte に続く引数は手続の評価時に評価される。
Document ID: ed2249c19e4d9fda414ebceb01a622f0
2012年04月10日
■ 電子書籍端末で小説を読もう
小説家になろうというサイトがある。 小説投稿サイトの中では比較的有名なようで、現時点で 15 万作品以上が掲載されている。 小説を読もう!というサイトもあり、こちらは「小説家になろう」に投稿された作品を読者向けに特化して紹介するサイトだ。
掲載作品は素人が書いているので大半の作品の質は大したものではないが、数が膨大なので根気よく探せば自分好みのものも見付かるだろう。
さて、読むにしても PC の画面で長時間読むのもダルいし、私は携帯電話等の携帯通信端末を持っていない。 だが、読書端末 Sony Reader (RPS-350) を持っているので、是非これで読みたいわけだ。 そういった動機により、「小説家になろう」のサイトの小説を電子書籍用のデータ形式 ePub に変換するスクリプトを作った。 そのスクリプトは Github で公開している。
https://github.com/SaitoAtsushi/yomou-publisher
使い方は簡単だ。 「小説家になろう」のサイトでは各作品をNコードという符号で管理しているので、そのコードを渡せばよい。 以下のような要領だ。
$ ypub.scm n0126r
小説のタイトルをファイル名とするファイルがカレントディレクトリに生成される。
残念ながらこのスクリプトが対応しているのは連載ものだけだ。 短編には対応していないので注意して欲しい。
オプションで -v を渡すと生成されるデータは縦書きになる。
$ ypub.scm -v n0126r
複数のNコードを同時に渡してもよい。
$ ypub.scm -v n0126r n3420r n2162k
ここまではスクリプトの使い方を説明したが、使う前にちょっとばかり前準備が必要なのでそれも説明しておこう。
スクリプトは Gauche を使って書いているので、大前提として Gauche がインストールされている必要がある。
http://practical-scheme.net/gauche/index-j.html
なるべく最新 (最新リリースではなくリポジトリの HEAD という意味) を用意するのが望ましい。 何故なら私が使っているのが HEAD だから。 細かな記法等で最新に依存している可能性がある。
あとは、文字コードの設定だ。 ファイル名に使われる文字コードを決める。
ypub.scm をエディタで開くと最初の方に
(define-constant *fsencode* 'Shift_JIS)
というのがあるので 'Shift_JIS のところを環境に合わせて設定して欲しい。 Windows なら 'Shift_JIS のままで良い。 Linux では最近のディストリビューションは 'utf-8 になっているだろう。 やや古いスタイルで運用しているなら 'euc-jp かもしれない。
Document ID: 6a97103387d09619da5f9f512881e7fb
2011年11月10日
■ こんな夢をみた「シュレ」
こんな夢をみた。
山の中の少しひらけたところにたくさんの老婆が集まっていた。 老婆達はまわりの木々の根本に落ちている乾いた小枝をたくさん集めて綺麗な円錐型に積み上げていく。
しばらく見ているとひとりの老婆が私に向かって話しかけてきた。
「これはね、『シュレ』という冬のための蓄えなんだよ」
2011年09月14日
■ explicit-renaming
LISP 系言語の強さの源泉のひとつがマクロにあることは疑いない。 だが、このマクロにはいくつもの方式がある。 Scheme の最新規格であるところの R6RS では syntax-case が採用されたが、それが最適な選択だと誰もが認めているわけではない。
意見が割れる理由は明白だ。
syntax-rules は不自由すぎるのだけれど、それ以外の衛生的マクロ、 syntax-case や explicit renaming 等はどれも力の上では同じであることがわかっていて、ひとつがあれば別のやつはポータブルに実装できることがわかっている。
http://blog.practical-scheme.net/shiro/20100425-scheme-macro
これは興味深い話だと思う。
マクロを使って別のマクロの方式を実装するというのをやってみようと思ったが、私は R5RS や R6RS 以外にあまり注目したことがなかったので、具体的にどんな方式があるのかと検索してみるととてもわかりやすい解説を見付けた。
http://d.hatena.ne.jp/leque/20080528/p1
比較的簡単そうに思えた Explicit Renaming (er-macro-transformer) を syntax-case で書いてみたのが以下だ。
#!r6rs (library (explicit-renaming) (export er-macro-transformer) (import (rnrs)) (define-syntax er-macro-transformer (lambda(x) (syntax-case x () ((k exp) (with-syntax ((identifier? (datum->syntax #'k 'identifier?))) #'(lambda(stx) (define (walk proc ls) (let loop ((ls ls)) (cond ((null? ls) '()) ((pair? ls) (cons (loop (car ls)) (loop (cdr ls)))) (else (proc ls))))) (define (rename sym) (datum->syntax #'k sym)) (syntax-case stx () ((t a (... ...)) (let* ((symbol->identifier (lambda(x) (if (symbol? x) (datum->syntax #'t x) x))) (compare (lambda(e1 e2) (let ((e1 (symbol->identifier e1)) (e2 (symbol->identifier e2))) (free-identifier=? e1 e2))))) (walk symbol->identifier ((let ((identifier? (lambda(e)(or (identifier? e) (symbol? e))))) exp) (syntax->datum #'(t a (... ...))) rename compare))))))))))) )
使用例も書いておく。
#!r6rs (import (rnrs) (for (explicit-renaming) expand)) (define-syntax swap! (er-macro-transformer (lambda (form rename compare) (let ((a (cadr form)) (b (caddr form))) `(,(rename 'let) ((,(rename 'value) ,a)) (,(rename 'set!) ,a ,b) (,(rename 'set!) ,b ,(rename 'value))))))) (define c 1) (define d 2) (swap! c d) (display c) (newline) (display d) (newline)
割と簡単に書けた。 Syntactic Closure を書くのもそれほど難しくはないのではないかと思う。
逆に Explicit Renaming や Syntactic Closure で syntax-case を書くのはとても面倒なものになるだろう。 そういう意味でユーザーとしての立場で見れば syntax-case はとても良いと思うのだが、機能を詰め込みすぎて Scheme の風潮に合わないというのもよくわかる。
次期規格である R7RS ではどうなることか。 Scheme の規格は改訂のたびに根本を変えすぎだよなぁ。
Document ID: 62aff67246b8a0ed93a20529ad56eef3
