2012-02-08 42 views
23

Tôi có một chức năng Haskell hiện có sử dụng API GHC để tự động tải mã biên dịch từ một mô-đun. Nó dựa trên mã từ bài đăng trên blog Dynamic Compilation and Loading of Modules in Haskell.GHC API - Cách tải động mã Haskell từ mô-đun được biên dịch bằng GHC 7.2?

Mã này hoạt động tốt trong GHC 7.0, nhưng đã được một chút thay đổi để biên dịch trong GHC 7.2, vì API GHC thay đổi.

Mã bây giờ ném một lỗi runtime trong GHC 7.2:

mkTopLevEnv: not a home module (module name):(function name) 

Mã này là

evalfuncLoadFFI String moduleName, 
       String externalFuncName, 
       String internalFuncName = do 

    result <- liftIO $ defaultRunGhc $ do 
    dynflags <- GHC.getSessionDynFlags 
    _ <- GHC.setSessionDynFlags dynflags 
    m <- GHC.findModule (GHC.mkModuleName moduleName) Nothing 

--------------------------------------------------------  
-- The following code works fine in GHC 7.0.4: 
-- 
-- GHC.setContext [] [(m, Nothing)] 
-- 
-- This new code attempts to set context to the module, 
-- but throws an error in GHC 7.2: 
-- 
    (_,oi) <- GHC.getContext 
    GHC.setContext [m] oi 
-------------------------------------------------------- 

    fetched <- GHC.compileExpr (moduleName ++ "." ++ externalFuncName) 
    return (Unsafe.Coerce.unsafeCoerce fetched :: [LispVal] -> IOThrowsError LispVal) 
    defineVar env internalFuncName (IOFunc result) 

Để tham khảo, mã đầy đủ có sẵn trực tuyến tại FFI.hs (github.com).

Có ai có bất kỳ ý tưởng làm thế nào để sửa chữa hoặc làm việc xung quanh vấn đề này?

Ngoài ra, điều này có thể được gây ra bởi sự an toàn Haskell mới thay đổi trong GHC 7.2, hoặc là nó chỉ do sửa đổi API GHC?

Trả lời

14

Bối cảnh mô-đun hiện nay được dành riêng cho các module hiện đang được biên soạn, tức là khi bạn xác định những module trong bối cảnh, họ phải dứt khoát không được bên ngoài.

Thay vào đó, bạn nên xác định các mô-đun truy nã như một nhập khẩu, trong đối số thứ hai của setContext. Điều này có thể được thực hiện như sau:

GHC.setContext [] 
    -- import qualified Module 
    [ (GHC.simpleImportDecl . GHC.mkModuleName $ moduleName) 
    { GHC.ideclQualified = True 
    } 
    -- -- import qualified Data.Dynamic 
    -- , (GHC.simpleImportDecl . GHC.mkModuleName $ "Data.Dynamic") 
    -- { GHC.ideclQualified = True 
    -- } 
    ] 
fetched <- GHC.compileExpr $ moduleName ++ "." ++ externalFuncName 
return . unsafeCoerce $ fetched 
-- or: 
-- fetched <- GHC.dynCompileExpr $ moduleName ++ "." ++ externalFuncName 
-- return . fromDynamic (error "Illegal type cast") $ fetched 

PS: nó có thể là một ý tưởng tốt để sử dụng GHC.dynCompileExpr thay vào đó, để bạn có thể tránh được những unsafeCoerce. Bạn phải thêm một nhập khẩu đủ điều kiện cho Data.Dynamic trong bối cảnh cho nó để làm việc, nhưng một giá trị Data.Dynamic.Dynamic nói chung là đẹp hơn để làm việc với, vì bạn có thể xử lý các lỗi kiểu cách duyên dáng hơn. Tôi đã thêm mã cho điều đó làm chú thích trong đoạn mã trên.


Cập nhật

Và đây là cú pháp cho GHC 7.4.1:

GHC.setContext 
    -- import qualified Module 
    [ GHC.IIDecl $ 
    (GHC.simpleImportDecl . GHC.mkModuleName $ moduleName) 
    {GHC.ideclQualified = True} 
    ] 
+0

Điều đó đã hoạt động hoàn hảo. Cảm ơn bạn về cú pháp thích hợp và giải thích chi tiết! Thưởng thức tiền thưởng của bạn :) –

+2

Tôi cũng đã thêm cú pháp cho GHC 7.4.1 trong trường hợp nó có thể có lợi cho bất kỳ ai khác. –

0

Hãy thử

GHC.setContext [] [(m,Nothing)] 

(từ another StackOverflow question)

+1

Xem chỉnh sửa gần đây của tôi; đây là mã tôi đang sử dụng cho GHC 7.0. Nhưng API đã thay đổi trong GHC 7.2 và 7.4 ... –

Các vấn đề liên quan