関数地獄:C編

今日の結論: Cは不完全言語だ(多分)。


諸事情により、C文法でコンビネータを書く必要がでてきた。
とりあえずSコンビネータを書いてみた(追記: よく考えたらこれ、カリー化忘れてる)。

combinator s(combinator f, combinator g, combinator x) {
  return f(x)(g(x));
}

これだけなら特に問題は無い。
問題は、combinator型を上手く定義できない事だ。


combinator型は、要するに、以下のような型だ。

  1. 「引数として関数ポインタを一つ取り、返り値として関数ポインタを一つ返す」関数のポインタ
  2. 但し、引数の関数ポインタも返り値の関数ポインタも、型はこの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でやる訳ではないので、ひとまずこれで諦める事にする。