For Gauche 0.9.5


Next: , Previous: , Up: 基本的な構文   [Contents][Index]

4.12 機能条件式

cond-expandマクロ

しばしば、実装やプラットフォームがどういった機能を提供しているかに 応じてコードを切り替えたいことがあります。例えば、ネットワークが使えるか どうかで振る舞いを変えるとか、ほぼポータブルなコードの一部だけに 特定の実装に依存するコードを入れたいとかいう場合です。

C言語なら、#ifdefのようなプリプロセッサディレクティブを、 Common Lispなら、#+#-のようなリーダマクロを使うところです。 Schemeでは、こういう時にはcond-expandを使います。

Macro: cond-expand (feature-requirement command-or-definition …) …

[SRFI-0][R7RS] プラットフォームがfeature-requirementに示される機能をサポートしていれば、 このマクロはcommand-or-definition … へと展開されます。

feature-requirement は以下のような構文でなければなりません。

feature-requirement
  : feature-identifier
  | (and feature-requirement …)
  | (or  feature-requirement …)
  | (not feature-requirement)
  | (library library-name)

このマクロは feature-requirement を順にテストし、そのひとつが 満たされたら、対応する command-or-definition … に展開されます。

最後の節のfeature-requirementの部分にはシンボルelseを 置くこともできます。他の節のfeature-requirementが満たされなかった場合に その節が展開されます。

条件を満たす節もelse節も無かった場合、cond-expandは エラーを通知します。この仕様は、 必要な機能を欠いている実行環境を早めに検出するためです。 もしチェックする機能がオプショナル、つまりそれが無くてもプログラムの実行自体は 可能であるというものであるなら、最後に空のelse節を忘れないようにしてください。

(cond-expand
  [feature expr]  ; some optional feature
  [else])

feature-identifier は機能を示すシンボルです。その機能が現在のプラットフォームで サポートされているなら、それは、feature-requirement を満たします。 より複雑な条件を構成するために、feature-requirement のブール代数による 組み合わせを用いることが出来ます。

(library library-name)という形式はR7RSで追加されたもので、 指定されるライブラリが使える場合に条件が満たされます。 これはR7RSの形式なので、ライブラリ名はリスト形式で指定します (gauche.netのかわりに(gauche net)等)。

例えば、Gauche、Chicken Scheme、ChibiSchemeに依存するコードを 入れたいとしましょう。現代の多くのScheme実装は、自分自身を示す feature-identifierを定義しているので、条件付きのコードは次のとおり書けます。

(cond-expand
 [gauche  (gauche-specific-code)]
 [(or chicken chibi) (chicken-chibi-specific-code)]
 [else    (fallback-code)]
 )

cond-expandの条件はマクロ展開時に全て処理され、 不採用だった節のコードは捨てられる、という事実は重要です。 このおかげで、例えば実装によって認識されないマクロ呼び出しや言語拡張を command-or-definitionに含めることができます。 また、グローバルな束縛を条件によって定義したりしなかったりすることができます。

これをcondと比較してみましょう。condは条件を実行時に調べます。 もし条件節の中に、あるプラットフォームではサポートされないマクロ呼び出しを 書いた場合、たとえその節が現実には決して実行されないものであるとしても、 マクロ展開時にエラーになってしまうかもしれません。 また、condを使って条件的にグローバルな束縛を定義することはできません。

ただし、マクロ展開した結果をどうにかして保存しておいて、 別のプラットフォームでそれを走らせる、ということをする場合は注意が必要です。 条件選択はマクロ展開をするプラットフォームの機能に応じて行われ、 それはコードを実行するプラットフォームの機能とは一致しないかもしれません (これはもちろん、クロスコンパイルで常に問題となることです。)

Gaucheで使えるfeature identifier一覧は下を見てください。

Gauche特有のfeature identifier

gauche
gauche-X.X.X

プログラムをGaucheで実行していることを示します。ポータブルなプログラムの中に Gauche特有のコードを埋め込むのに便利です。 X.X.XはGaucheのバージョンで(例: gauche-0.9.4)、 特定のGaucheのバージョンのみに依存したコードを入れるのに使えます。 (処理系のバージョンつきの機能識別子はR7RSで示唆されているものですが、 バージョンを比較する機能がないとあまり有用ではないでしょう。 将来はそのような機能が追加されるかもしれません。)

gauche.os.windows
gauche.os.cygwin

それぞれ、WindowネイティブプラットフォームとCygwin/Windowsプラットフォームを 示します。どちらも定義されていなければ、Unix系と考えて構いません。 (CygwinもUnix系と言えなくはありませんが、他のUnix系に比べて 色々違いがあるので、機能識別子を用意してあります。)

gauche.ces.utf8
gauche.ces.eucjp
gauche.ces.sjis
gauche.ces.none

これらのうちのいずれか一つが、Gaucheの内部エンコーディングに合わせて 定義されます。詳しくはマルチバイト文字列を参照してください。

gauche.net.tls

TLS/SSLサポートがあれば定義されます。

gauche.net.ipv6

IPv6サポートが組み込まれていれば定義されます。 ただし、これがGaucheがIPv6サポート込みでビルドされたことを示すだけです。 OSがIPv6サポートをオフにしている場合、IPv6機能を使おうとするとシステムエラーが 投げられます。

gauche.sys.threads
gauche.sys.pthreads
gauhce.sys.wthreads

マルチスレッドがサポートされていればgauche.sys.threadsが定義されます (スレッド参照)。また、マルチスレッドは内部ではプラットフォームによって POSIXスレッドかWindowsスレッドを利用しますが、前者の場合は gauche.sys.pthreadsが、後者ではgauche.sys.wthreadsが 併せて定義されます。

gauche.sys.sigwait
gauche.sys.setenv
gauche.sys.unsetenv
gauche.sys.clearenv
gauche.sys.getloadavg
gauche.sys.getrlimit
gauche.sys.lchown
gauche.sys.getpgid
gauche.sys.nanosleep
gauhce.sys.crypt
gauche.sys.symlink
gauche.sys.readlink
gauche.sys.select
gauche.sys.fcntl
gauche.sys.syslog
gauche.sys.setlogmask
gauche.sys.openpty
gauche.sys.forkpty

これらシステムの機能が使えるのなら対応する機能識別子が定義されます。

R7RSで定義されたfeature identifiers

r7rs

実装がr7rs準拠であることを示します。

exact-closed

数値計算が正確な値について閉じている、つまり、正確な数を ゼロ以外の正確な数で割った結果が常に正確な数になることを示します。

ieee-float

内部的にIEEE浮動小数点数を使っていることを示します。

full-unicode

Unicodeの全ての範囲をサポートしていることを示します。

ratios

有理数のサポートがあることを示します。

posix
windows

プラットフォームによってどちらかが定義されます。

big-endian
little-endian

プラットフォームによってどちらかが定義されます。


Next: , Previous: , Up: 基本的な構文   [Contents][Index]