Tôi đang thử nghiệm với giao diện chức năng nước ngoài trong Haskell. Tôi muốn thực hiện một bài kiểm tra đơn giản để xem tôi có thể làm đệ quy lẫn nhau không. Vì vậy, tôi đã tạo mã Haskell sau đây:Biên dịch tối ưu hóa cuộc gọi đuôi trong đệ quy lẫn nhau trên C và 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()
Lưu ý rằng trường hợp đệ quy là cuộc gọi đếm ngượcC, vì vậy điều này cần phải đệ quy đuôi.
Trong mã C của tôi, tôi 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;
}
Đó là tương tự như vậy đuôi đệ quy. Vì vậy, sau đó tôi thực hiện một
MutualRecursion: MutualRecursionHaskell_stub
ghc -O2 -no-hs-main MutualRecursionC.c MutualRecursionHaskell.o -o MutualRecursion
MutualRecursionHaskell_stub:
ghc -O2 -c MutualRecursionHaskell.hs
và biên dịch với make MutualRecursion
.
Và ... khi chạy, nó sẽ được phân tách sau khi in 8991
. Cũng giống như một bài kiểm tra để đảm bảo gcc chính nó có thể xử lý TCO trong đệ quy lẫn nhau, tôi đã làm
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);
}
và làm việc khá tốt. Nó cũng hoạt động trong trường hợp đệ quy đơn lẻ chỉ trong C và chỉ trong Haskell.
Vì vậy, câu hỏi của tôi là, có cách nào để chỉ ra cho GHC rằng cuộc gọi đến hàm C bên ngoài có đuôi đệ quy không? Tôi giả định rằng khung ngăn xếp đến từ cuộc gọi từ Haskell đến C và không phải là cách khác xung quanh, vì mã C là rất rõ ràng một sự trở lại của một cuộc gọi chức năng.
Có cách nào để ngăn các vị trí trả lại kép không? Ví dụ, tôi đã viết một thói quen thay thế bằng cách sử dụng mô hình phù hợp (đối với 0 cho trường hợp cơ sở), nhưng điều đó không giúp đỡ. Nói chung, có cách nào tel tel bảo GHC biên dịch theo một cách để cho phép đệ quy đuôi qua ranh giới? – Crazycolorz5
@ Crazycolorz5 Điều chỉnh thời gian chạy là một nhiệm vụ rất khó khăn. Bạn dường như tin rằng đó là GHC nên thích ứng với thời gian chạy của nó theo chuẩn C. Để tìm ra khó khăn như thế nào, suy nghĩ về cách khác xung quanh: sửa đổi GCC để cho phép cho nhiều lợi nhuận, bộ sưu tập rác, vv Đó là bên cạnh không thể. Những gì bạn yêu cầu là rất, rất khó đạt được với GHC hiện tại, hoặc thậm chí trong tương lai xa như tôi có thể thấy. – chi