Dynamic Module Name

I want to do something similar in Haskell, but the compiler does not allow me.

Is there any way to accomplish this task?

-- both modules export function named "hello" -- and I want to run it in every module import qualified MyMod as M1 import qualified MyAnotherMod as M2 runmodules = map (\m -> m.hello) [M1, M2] 
+7
source share
3 answers

I don’t think you can specify a qualified name prefix like this in the haskell template, and the hello identifier is not in scope, so you may have to go back to programming with strings.

 module ModuleParamsTH where import Language.Haskell.TH getAll :: String -> [String] -> ExpQ getAll valueName moduleNames = listE $ map (varE . mkName . (++ suffix)) moduleNames where suffix = "." ++ valueName 

which can then be used so

 {-# LANGUAGE TemplateHaskell #-} import ModuleParamsTH import qualified ModuleParamsM1 as M1 import qualified ModuleParamsM2 as M2 runmodules = $(getAll "hello" ["M1", "M2"]) 

However, I would not do all this. You can simply write [M1.hello, M2.hello] or use a type class to abstract over implementations.

+5
source

Haskell modules are not even remotely first-class entities, as may be required, I'm afraid.

However, as bzn commented, Template Haskell can be used for such problems. The result may be a little awkward, but if you really need fast metaprograms, this is not a bad choice. I am not an expert with TH, but what you want is pretty simple, with one catch: neither "ambiguous identifiers" nor "module names" can be fixed or quoted in any way, as far as I know, I have to put them to the strings specified as arguments to the TH function.

Here is a quick and dirty, minimal example:

 {-# LANGUAGE TemplateHaskell #-} module MapModuleTH where import Language.Haskell.TH mapQual :: [String] -> String -> ExpQ mapQual ms n = listE $ map (\m -> varE . mkName $ m ++ "." ++ n) ms mapMQual :: [String] -> String -> ExpQ mapMQual ms n = appE (varE 'sequence) $ listE $ map (\m -> varE . mkName $ m ++ "." ++ n) ms 

You have formulated things as “launching a function”, which is more like doing a few IO actions, and not just collecting a list of things, so I added an option that also organizes the result.

Please note that despite the use of strings here, it is still statically typed - if the names do not exist or the types do not match, you will get the expected compile-time error just as if you wrote everything manually.

Here is a brief example of its use. Given the following:

 {-# LANGUAGE TemplateHaskell #-} module MapModule where import MapModuleTH import qualified Test1 as T1 import qualified Test2 as T2 tests = do xs <- $(mapMQual ["T1", "T2"] "test") putStrLn $ "Count: " ++ show (length xs) 

Assuming that other modules exist and define test , in GHCi we can see:

 > tests Test 1 Test 2 Count: 2 
+8
source

Modules are not values ​​in Haskell. Therefore it is impossible. What do you want to achieve?

+3
source