Модули в Haskell даже не являются удаленно первоклассными объектами в способах, которые это потребует, я боюсь.
Однако, как прокомментировал bzn, Template Haskell можно использовать для подобных задач.Результат может быть немного неуклюжим, но если вам действительно нужно несколько быстрых хаков метапрограммирования, это не плохой выбор.Я не очень разбираюсь в TH, но то, что вы хотите, довольно просто, с одним уловом: ни «неоднозначные идентификаторы», ни «имена модулей» не могут быть захвачены или указаны в кавычках, насколько я знаю, так чтоПридется поместить их в строки, заданные в качестве аргументов функции TH.
Вот быстрый и грязный, минимальный пример:
{-# 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
Вы сформулировали вещи как «запуск функции», что больше похоже на выполнение IO
действий, а не просто сборсписок вещей, поэтому я добавил вариант, который также упорядочивает результат.
Обратите внимание, что, несмотря на использование здесь строк, этот является все еще статически типизированным - если квалифицированные имена неЕсли вы не существуете или типы не совпадают, вы получите ожидаемую ошибку во время компиляции, как если бы вы выписали все вручную.
Вот краткий пример ее использования.Учитывая следующее:
{-# 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)
Предполагая, что есть другие модули и определяя test
, тогда в GHCi мы можем видеть:
> tests
Test 1
Test 2
Count: 2