Ich experimentiere mit der Fremdfunktionsschnittstelle in Haskell. Ich wollte einen einfachen Test implementieren, um zu sehen, ob ich eine gegenseitige Rekursion durchführen kann. Also, habe ich den folgenden Haskell Code:Kompilierung der Tail-Call-Optimierung bei der gegenseitigen Rekursion in C und 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()
Beachten Sie, dass die rekursive Fall ist ein Aufruf an countdownC, so sollte dies sein Schwanz-rekursiv.
In meinem C-Code, habe ich
#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;
}
die ebenfalls Schwanz rekursiv ist. Also dann mache ich einen
MutualRecursion: MutualRecursionHaskell_stub
ghc -O2 -no-hs-main MutualRecursionC.c MutualRecursionHaskell.o -o MutualRecursion
MutualRecursionHaskell_stub:
ghc -O2 -c MutualRecursionHaskell.hs
und kompilieren mit make MutualRecursion
.
Und ... nach dem Drucken segfaults nach dem Drucken 8991
. Nur als Test sicher gcc machen sich tco in gegenseitige Rekursion umgehen kann, habe ich
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);
}
und das funktionierte sehr gut. Es funktioniert auch im Einzel-Rekursions-Fall von nur in C und nur in Haskell.
Meine Frage ist also, gibt es eine Möglichkeit, GHC anzuzeigen, dass der Aufruf der externen C-Funktion Tail rekursiv ist? Ich gehe davon aus, dass der Stack-Frame vom Aufruf von Haskell nach C kommt und nicht umgekehrt, da der C-Code sehr deutlich eine Rückgabe eines Funktionsaufrufs ist.
Gibt es eine Möglichkeit, die Doppelrücklauforte zu verhindern? Zum Beispiel schrieb ich eine alternative Routine mit Mustererkennung (gegen 0 für den Basisfall), aber das half nicht. Gibt es generell eine Möglichkeit, GHC so zu kompilieren, dass eine Tail-Rekursion über die Grenze möglich ist? – Crazycolorz5
@ Crazycolorz5 Anpassung der Laufzeit ist eine sehr schwierige Aufgabe. Sie scheinen zu glauben, dass GHC seine Laufzeit an den C-Standard anpassen sollte. Um herauszufinden, wie schwer das ist, denke über den umgekehrten Weg nach: Modifizieren von GCC, um Mehrfachrückgaben, Speicherbereinigungen usw. zu ermöglichen. Es ist nahezu unmöglich. Was Sie fragen, ist sehr, sehr unwahrscheinlich, mit der aktuellen GHC erreicht werden, oder sogar in der fernen Zukunft, soweit ich sehen kann. – chi