module Main where import Control.Monad import Data.Maybe import Data.Typeable import Language.Haskell.Interpreter import System.Environment (getArgs) import qualified Data.Set as S import Data.Set (Set) -- For demonstration purposes, this program will load it's configuration from a -- file specified in the command line, and print out the resulting configuration -- (or error messages): main :: IO () main = do args <- getArgs when (null args) (fail "Must pass configuration file as parameter") config <- loadConfig (head args) case config of Left err -> fail ("Could not load configuration:" ++ show err) Right c -> runApp c runApp :: Config -> IO () runApp config = putStrLn . show $ config -- The datatype the configuration will ultimately be stored in: data Config = Config { cBaseUrl :: String , cPort :: Maybe Int } deriving Show -- The loadConfig function actually does the interesting work: loadConfig :: String -> IO (Either InterpreterError Config) loadConfig file = runInterpreter $ do set [languageExtensions := [ExtendedDefaultRules]] -- use extended defaulting rules to get the numeric types we really want loadModules [file] getLoadedModules >>= setTopLevelModules setImports ["Prelude"] params <- fmap (S.fromList . mapMaybe getFunction) $ getModuleExports "Main" port <- maybeInterpret params "port" (as :: Int) url <- interpret "baseUrl" (as :: String) return $ Config url port getFunction :: ModuleElem -> Maybe Id getFunction (Fun i) = Just i getFunction _ = Nothing maybeInterpret :: (MonadInterpreter m, Typeable a) => Set Id -> String -> a -> m (Maybe a) maybeInterpret s t w = if S.member t s then liftM Just $ interpret t w else return Nothing