2013-04-05 14 views
11

Próbuję załadować i uruchomić moduł dynamicznie,GHC 7.4.2 dynamicznie wywołanie moduły

Poniżej jest mój kod

TestModule.hs

module TestModule 
     where 

evaluate = "Hello !!!" 

Invoke.hs

module Invoke 
     where 

import GHC 
import DynFlags 
import GHC.Paths (libdir) 
import Unsafe.Coerce (unsafeCoerce) 
import Data.Dynamic 

execFnGhc :: String -> String -> Ghc a 
execFnGhc modname fn = do 
     mod <- findModule (mkModuleName modname) Nothing 
     --setContext [IIModule mod] 
     GHC.setContext [ GHC.IIDecl $ (GHC.simpleImportDecl . GHC.mkModuleName $ modname) {GHC.ideclQualified = True} ] 
     value <- compileExpr (modname ++ "." ++ fn) 
     let value' = (unsafeCoerce value) :: a 
     return value' 

Main2.hs

import GHC.Paths (libdir) 
import GHC 
import Invoke 
-- import TestModule 

main :: IO() 
main = runGhc (Just libdir) $ do 
         str <- execFnGhc "TestModule" "evaluate" 
         return str 

Kiedy próbuję uruchomić program, to pokaż mi poniżej błędu

[[email protected] mypproj]# ./Main2 
Main2: <command line>: module is not loaded: `TestModule' (./TestModule.hs) 

Nie wiem, czego mi brakuje, Czy ktoś mógłby mi pomóc rozwiązać ten problem

+0

Nie wiem zbyt wiele na ten temat, ale wygląda na to, że można to zrobić znacznie łatwiej dzięki [wtyczkom] (http: //hackage.haskell. pakiet org/pakiet/wtyczki). – Almanildo

Odpowiedz

1

Moje myśli byłby problem ma coś zrobić ze swoją ścieżką, a program cicho pomyłki, gdy nie może załadować "TestModule", a następnie skarży się, że moduł nie jest ładowany. Czy próbowałeś użyć execFnGhc z modułem, który jest już załadowany, i czy próbowałeś załadować moduł, który jest w GHC w sposób naturalny, taki jak Text.Parsec, a następnie wykonując coś w nim?

Sprawdziłbym siebie, ale nigdzie nie widzę biblioteki GHC.Paths: /.

+0

Próbowałem długość listy, str <- execFnGhc "Data.List" "length [1,2,3]", ale rzuca wyjątek jako "Main: Main: panika! (Stało się" niemożliwe ") (Wersja GHC 7.4.2 dla x86_64-unknown-linux): \t żadne państwo pakiet jeszcze call GHC.setSessionDynFlags Proszę zgłosić to jako błąd GHC: http://www.haskell.org/ghc/reportabug " – Xinus

+0

od błąd, wygląda na to, że zanim będziesz mógł użyć execFnGhc, musisz ustawić "flagi sesji" dla GHC. Spróbuj spojrzeć na rodzaj GHC.setSessionFlags i może zobaczenie, czy istnieje "GHC.getSessionFlags"; wygląda na to, że GHC potrzebuje więcej informacji, zanim będzie mógł nazwać rzeczy. –

0

Ostatnio czytałem odpowiedni kod źródłowy GHC i wygląda na to, że findModule nie działa w modułach lokalnych (TestModule.hs w twoim przypadku), chyba że zostały już załadowane. (Działa to jednak w modułach zdalnych pakietów).

Aby wykonać dynamiczne ładowanie skompilowanych modułów w stylu GHCi, najlepiej jest użyć addTarget i load. Jak wspomniano w komentarzach, musisz także zainicjować dynamiczne flagi sesji. Oto działająca wersja Twojego kodu:

module Invoke 
     where 

import GHC 
import DynFlags 
import GHC.Paths (libdir) 
import Unsafe.Coerce (unsafeCoerce) 
import Data.Dynamic 

execFnGhc :: String -> String -> Ghc String 
execFnGhc modname fn = do 
     dflags <- getDynFlags 
     setSessionDynFlags dflags 
     let target = Target (TargetModule (mkModuleName modname)) True Nothing 
     addTarget target 
     load (LoadUpTo (mkModuleName modname)) 
     mod <- findModule (mkModuleName modname) Nothing 
     GHC.setContext [ GHC.IIDecl $ (GHC.simpleImportDecl . GHC.mkModuleName $ modname) {GHC.ideclQualified = True} ] 
     value <- compileExpr (modname ++ "." ++ fn) 
     let value' = (unsafeCoerce value) :: String 
     return value' 

Jakie są parametry Target? Pierwsza to nazwa modułu; drugim jest to, czy powinniśmy mieć możliwość załadowania kodu obiektowego, czy też zawsze interpretować moduł; the last jest opcjonalnym buforem ciągów znaków, którego można użyć do zastąpienia kodu źródłowego w rzeczywistym pliku (jest to Nothing, ponieważ nie jest nam to potrzebne).

Jak to zrozumiałem? Spojrzałem na kod używany przez GHCi do implementacji tego w kodzie źródłowym GHC, a także na compiler/main/GHC.hs. Odkryłem, że jest to najbardziej niezawodny sposób, aby dowiedzieć się, jak uzyskać interfejs API GHC, aby zrobić to, co chcesz.

Mylące? Interfejs API GHC nie był tak zaprojektowany, jak akrylowany ...