2013年06月16日

include とマクロ

R7RS draft 9 によれば、 include 構文は including file を含むディレクトリの中のファイルを検索するべきとある。
例えば以下のようなプログラムがあったとすると、


foo/x.scm:
(include "z.scm")


including file であるところの foo/x.scm を含むディレクトリ foo の中のファイル z.scm 、つまり foo/z.scm ということであろう。
こういう単純な例なら何も問題はない。
しかしマクロが絡むと、事態は複雑になる。
例えば以下のような場合どうするか?


foo/x.scm:
(include "../bar/y.scm")
(includez)

bar/y.scm:
(define-syntax includez
(syntax-rules ()
((_)
(include "z.scm"))))


普通に考えると、マクロ includez は foo/x.scm 内に展開され、 foo/z.scm をインクルードするべきように思える。
しかし hygiene 的にいえば、 (include "z.scm") しているのはあくまで bar/y.scm であるから、そこをベースに bar/z.scm をインクルードするべきではないだろうか。
マクロの使用場所によって foo/z.scm になったり hoge/z.scm になったりしてはいまいち使いにくい。
しかし以下のような場合はどうする?


foo/x.scm:
(include "../bar/y.scm")
(inc "z.scm")

bar/y.scm:
(define-syntax inc
(syntax-rules ()
((_ name)
(include name))))


実際に include を呼んでいるのは b/y.scm であるといっても、ファイル名 "z.scm" を指定しているのは foo/x.scm であって、この場合 foo/z.scm をインクルードするべきであろう。

と、ここまで考えて、たぶん文字列 "z.scm" の出所を追跡し、その場所をベースにするのが良さそうに思えてきた。
posted by milkpot at 18:33| Comment(0) | Scheme

2013年02月06日

On Lisp

を読んだ。
とりあえず、 Lisp のマクロ読みにくい。
掲載されてる Lisp のコードはほとんどスルーして本文だけ読んだ。

amb。
そういえばそんなものがあるんだった。
call/cc が軽ければ amb を活用しまくるのは面白そう。
でもその場合 amb はスレッドセーフじゃないと困る。
グローバル変数に状態を保存するっていうのはイマイチ。

パーサジェネレータ。
パーサというか、レキサかな。
どっちにせよ、そういうのを手で書くのは面倒いので、
なにか上手いことマクロで生成できると確かに楽かもしれない。
posted by milkpot at 23:26| Comment(0) | Scheme

2012年12月07日

R7RS draft 7

がいつのまにか公開されていました。

斜め読みしてみて気になった点:
・inexact->exact が単に exact という名前に
・exact->inexact が単に inexact という名前に
・real? の要件から exact? が消えた
・cond-expand の中で library の有無が判定できる
・feature のリストを返す手続き features
・eof-object を返す手続き eof-object
・promise を作る手続き make-promise
・promise を判別する述語 promise?
・boolean を比較する手続き boolean=?
・シンボルを比較する手続き symbol=?
・エラーの種類を判別する述語 file-error? と read-error?
・多値で変数定義する構文 define-values
・write が write, write-shared, write-simple の 3 種類になった
・範囲指定できる手続きがやたら増えた
・NaN に対する eqv? が未規定である旨が明記された
・string-ref と string-set! が定数時間でなくてよい旨が明記された
・他のファイルからライブラリ定義を取り込む include-library-declarations
・caar ... cddddr が (scheme cxr) という名前の新しいライブラリに移動
・read が (scheme read) という名前の新しいライブラリに移動
・display, write, write-shared, write-simple が (scheme write) という名前の新しいライブラリに移動
・R5RS 互換の手続きと構文を提供する (scheme r5rs) という名前の新しいライブラリが追加
posted by milkpot at 01:47| Comment(3) | Scheme

2012年03月08日

(number->string 0.1)

RnRS には number->string に関して以下のような記述がある。

If z is inexact, the radix is 10, and the above expression can be satisfied by a result that contains a decimal point, then the result contains a decimal point and is expressed using the minimum number of digits (exclusive of exponent and trailing zeroes) needed to make the above expression true

例えば (number->string 0.1) を考えてみよう。
戻り値として "0.1" や "1.0e-1" などが考えられるが、
上記に従えば "0.1" は 2 桁の数字であり (前のゼロは除かない)、
"1.0e-1" は 1 桁の数字であり (指数と後ろのゼロは除く)、
当然 1 桁の方が最小なわけであるから、
(number->string 0.1) は "0.1" ではなく "1.0e-1" を返さなければならない。
別に "10.0e-2" とか "100.0e-3" でもいいが、 "0.1" とか "0.01e1" とかは許されない。

つまり何が言いたいかというと、
(number->string 0.1) が "0.1" を返す処理系はみんなバグってることになるよね?
posted by milkpot at 00:56| Comment(0) | Scheme

2012年02月25日

数値に対する eqv?

R7RS によれば、 eqv? は以下の場合に #t を返す。

obj1 and obj2 are both numbers, are numerically equal (see =, section 6.2), and are either both exact or both inexact.

ということは、以下の式は #t を返すことになる。

(eqv? 1.0s0 1.0d0)

number->string の意味は eqv? で定義されているから、 1.0s0 を number->string して string->number したら 1.0d0 になっていてもいいことになる。

あと、今気づいた、気になる記述が。

Negative zero is an inexact real value written -0.0 which is distinct (in the sense of eqv?) from 0.0.

eqv? は 0.0 と -0.0 を区別するらしい。
posted by milkpot at 20:46| Comment(0) | Scheme