2015-03-12 1 views
1

Есть ли способ в компиляторе Glasgow Haskell для анализа имен всех функций в модуле?Имена функциональных функций в модуле GHC

Я пытаюсь создать автоматическую систему миграции баз данных, которая, учитывая имена модулей миграции, анализирует имена функций внутри и вызывает их по одному.

Что-то вроде

doMigrations("Migrations.M_2015") 
doMigrations("Migrations.M_2016") 
-- ... 

где Migration.M_2015 содержит

module Migration.M_2015 
where 

migration_2015_01_02 :: DbConnection -> Status 
migration_2015_01_02 connection = 
    -- ... 

Каждый doMigration будет отражать имена функций миграции в модуле и вызывать только те, которые не были запустить ранее (имен, сохраненных в таблица БД). Это будет вызвано только при запуске приложения, поэтому производительность не является большой проблемой. Отражение может происходить либо во время компиляции, либо во время выполнения.

+0

Существует: Это называется Template Haskell. Это не так просто.Несколько поисков Google должны позволять вам отслеживать, какая небольшая документация существует для него. – MathematicalOrchid

+2

Есть ли причина, по которой вы не можете выполнить 'migrationsToDo = [migration_2015_01_02, ...]', а затем просто 'map doMigrations migrationsToDo'? Вам не нужна какая-либо интроспекция; похоже, вы ничего не делаете с именами, просто вызываете функции. – user2407038

+0

И добавление их в таблицу уже запущенных миграций. – Ralph

ответ

1

Для этого вам необходимо использовать API GHC - который включен в пакет ghc (который скрыт) - и плохо документирован.

Прилагаю здесь простую программу, которая распечатает список элементов верхнего уровня, экспортированных в модуль. Это должно послужить отправной точкой. Это небольшая утилита командной строки, которая принимает два аргумента - имя модуля и слово «класс», «данные», «функция». Так, например:

test Prelude function

напечатает список функций, экспортируемых модулем (те, которые не являются конструкторами или определить в классе).

Для того, чтобы скомпилировать это (при условии, что в test.hs) вам нужно будет сделать:

ghc -package ghc test

для того, чтобы пакеты GHC API доступны.

Вот код:

import Data.List ((\\)) 
import Data.Maybe (fromJust, catMaybes) 
import System.Environment (getArgs) 

-- the GHC API stuff 

import GHC 
import GHC.Paths (libdir) 
import ConLike (ConLike(..)) 
import Outputable (showPpr, showSDocUnqual) 
import Var (tyVarName) 

showU dfs = showSDocUnqual dfs . pprParenSymName 

main = do 
    (mn : ty : _) <- getArgs 
    a <- runGhc (Just libdir) $ do 
    dflags <- getSessionDynFlags 
    setSessionDynFlags dflags 
    mm <- lookupModule (mkModuleName mn) Nothing 
    mi <- fmap fromJust $ getModuleInfo mm 
    res <- fmap catMaybes $ mapM lookupName (modInfoExports mi) 
    return $ case ty of 
     "class" -> [showU dflags c' | [email protected](ATyCon c') <- res, isClassTyCon c'] 
     "data" -> [showU dflags c' | [email protected](ATyCon c') <- res, (not . isClassTyCon) c'] 
     "function" -> let cf = map getName $ concat [(classMethods . fromJust . tyConClass_maybe) c' | [email protected](ATyCon c') <- res, isClassTyCon c'] 
         df = map getName $ concat [ tyConDataCons c' | [email protected](ATyCon c') <- res, (not . isClassTyCon) c'] 
         ff = [ getName c | [email protected](AnId{}) <- res] \\ cf 
         fd = [ getName c | [email protected](AConLike (RealDataCon{})) <- res] \\ df 
        in [showU dflags x | x <- ff ++ fd] 
     _ -> ["need to specify: class, data, or function"] 
    print a 

Список классов и определенных данных довольно проста. Список определенных функций включает функции, определенные в классах и конструкторах. Вышеприведенный код для функций исключает их (с \\ cf и \\ df).

a - это сгенерированный список имен функций (или классов или данных).

Код, который будет ссылаться на эти функции, будет предметом другого вопроса (и ответа).

lookupModule - это функция, которая загружает модуль для анализа.

Сочетание getModuleInfo и modInfoExports получает список «материала», который включает в себя список функций, экспортируемых из модуля.

Остальная часть кода касается получения этих имен в пригодной для использования форме.

Смежные вопросы