関数地獄:C編
今日の結論: Cは不完全言語だ(多分)。
諸事情により、C文法でコンビネータを書く必要がでてきた。
とりあえずSコンビネータを書いてみた(追記: よく考えたらこれ、カリー化忘れてる)。
combinator s(combinator f, combinator g, combinator x) { return f(x)(g(x)); }
これだけなら特に問題は無い。
問題は、combinator型を上手く定義できない事だ。
combinator型は、要するに、以下のような型だ。
- 「引数として関数ポインタを一つ取り、返り値として関数ポインタを一つ返す」関数のポインタ
- 但し、引数の関数ポインタも返り値の関数ポインタも、型はこのcombinator型
もし、第一条件だけでいいなら、以下のようになる。
typedef void*(*combinator)(void*);
しかし、void*では毎回型キャストが必要になってしまうので、第二条件を使って、引数と返り値の型も指定する。
typedef combinator(*combinator)(combinator);
しかしこれが、typedefが再帰的定義を受け付けない為、コンパイルが通らない。
色々考えたが、上手い記述方法は思い付かなかった。
と言うか、どうも不可能なように思える。
型キャストを使う以外に無いのか?
typedef void*(*combinator)(void*); combinator s(combinator f, combinator g, combinator x) { return ((combinator)f(x))(g(x)); }
分かりにくい……。
これなら最初からcombinator型なんか導入せずに、何もかも全部void*の方がまだマシでは、と少し考えたが、そうするとapply動作を行う毎に毎回、長ったらしい関数ポインタの型キャスト宣言が必要になる。
しかし毎回、どこで型キャストが必要になるのかを、コンパイル時の警告と人間の脳味噌を使って判定するよりは、マクロを使って上手くラッピングした上で、実体はさっきの「全部void*で毎回型キャスト」方式でやるのが一番マシなんだろうな、とは思う。
とりあえず今のところは、別に本式にコンビネータ操作をCでやる訳ではないので、ひとまずこれで諦める事にする。