Haskell で外部関数インターフェイスを試しています。相互再帰を実行できるかどうかを確認する簡単なテストを実装したかったのです。そこで、次の Haskell コードを作成しました。
module MutualRecursion where
import Data.Int
foreign import ccall countdownC::Int32->IO ()
foreign export ccall countdownHaskell::Int32->IO()
countdownHaskell::Int32->IO()
countdownHaskell n = print n >> if n > 0 then countdownC (pred n) else return ()
再帰的なケースはcountdownCの呼び出しであるため、これは末尾再帰でなければならないことに注意してください。
私のCコードでは、
#include <stdio.h>
#include "MutualRecursionHaskell_stub.h"
void countdownC(int count)
{
printf("%d\n", count);
if(count > 0)
return countdownHaskell(count-1);
}
int main(int argc, char* argv[])
{
hs_init(&argc, &argv);
countdownHaskell(10000);
hs_exit();
return 0;
}
これは同様に末尾再帰です。だから私は
MutualRecursion: MutualRecursionHaskell_stub
ghc -O2 -no-hs-main MutualRecursionC.c MutualRecursionHaskell.o -o MutualRecursion
MutualRecursionHaskell_stub:
ghc -O2 -c MutualRecursionHaskell.hs
でコンパイルしmake MutualRecursion
ます。
そして...実行すると、印刷後にセグメンテーション違反が発生します8991
。gcc 自体が相互再帰で tco を処理できることを確認するためのテストとして、
void countdownC2(int);
void countdownC(int count)
{
printf("%d\n", count);
if(count > 0)
return countdownC2(count-1);
}
void countdownC2(int count)
{
printf("%d\n", count);
if(count > 0)
return countdownC(count-1);
}
そしてそれは非常にうまくいきました。また、C と Haskell のみの単一再帰の場合でも機能します。
私の質問は、外部 C 関数の呼び出しが末尾再帰であることを GHC に示す方法はありますか? Cコードは明らかに関数呼び出しのリターンであるため、スタックフレームはHaskellからCへの呼び出しから来ており、その逆ではないと仮定しています。