我正在用Haskell中的外部函數接口進行試驗。我想實施一個簡單的測試,看看我能否做到相互遞歸。所以,我創建了下面的Haskell代碼:在C和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
編譯。
And ...運行時,打印後出現段錯誤8991
。 就像一個測試,以確保海合會本身可以相互遞歸處理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中的單一遞歸情況。
所以我的問題是,有沒有辦法向GHC表明對外部C函數的調用是尾遞歸?我假設堆棧框架確實來自Haskell對C的調用,而不是其他方式,因爲C代碼非常清楚地返回了函數調用。
有沒有辦法來防止雙返回地點?例如,我使用模式匹配編寫了一個備用例程(對於基本情況爲0),但這並沒有幫助。一般來說,有沒有一種方法可以告訴GHC以一種允許跨越邊界遞歸的方式進行編譯? – Crazycolorz5
@ Crazycolorz5調整運行時間是一項非常艱鉅的任務。你似乎相信GHC應該把它的運行時間調整到C標準。要弄清楚這是多麼困難,請考慮其他方式:修改GCC以便允許多個返回,垃圾回收等。這幾乎是不可能的。就目前的GHC而言,甚至在我看來,即使在遙遠的將來,你所要求的是非常非常不可能實現的。 – chi