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

Я определил множество функций (скажем, более 100), каждая из которых выполняет определенную работу, но с одной и той же сигнатурой. Это что-то вроде:

module R001 (run) where run = <do-...>
module R002 (run) where run = <do-...>

Что я хочу сделать, так это предоставить фактический «запуск» в качестве пользовательского ввода, например:

main = do
         runWith $ read $ getLine
       where
         runWith :: Int -> IO ()
         runWith n = R<n-padded-with-0>.run

В настоящее время я импортирую все квалифицированные модули и помещаю все run в список [Maybe (IO())], так что это работает:

runWith n = case Rs !! (read $ getLine) of 
              Just run -> run
              Nothing -> undefined

Но по мере роста n мне приходится постоянно вести большой список.

Есть ли способ определить большой список с помощью TemplateHaskell или просто загрузить соответствующий модуль по мере необходимости во время выполнения без необходимости разделения каждого модуля на разные общие библиотеки.


Основываясь на ответе epsilonhalbe, я провел небольшое исследование:

import R1 (run1)
import R2 (run2)

test = $(functionExtractor "^run")

main :: IO ()
main = do
         putStrLn $ show $ length $ test
         run1 -- remove on second attempt
         run2 -- remove on second attempt

Этот блок кода выводит 2 по результатам run1 и run2. Если я удалю последние две строки, он просто напечатает 0. Кажется, что импортированные функции, на которые не ссылаются, не будут извлечены...


person claude    schedule 05.09.2011    source источник


Ответы (2)


У меня когда-то была похожая проблема модуль загрузки haskell в списке, возможно, это поможет.

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

import R*.hs (run)

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

{-# LANGUAGE TemplateHaskell #-}
import Language.Haskell.Extract
import myRunFunctions

main = do
     let listOfRuns = $(functionExtractor "^run")
     putStrLn "please choose a run"
     putStrLn $ show listOfRuns
     let run = runWith $ read $ getLine
     run
   where
     runWith n = listOfRuns !! n

Внимание: я не запускал этот код, это просто поток мыслей, заложенный в синтаксисе haskell.

я надеюсь, что это полезно


После редактирования:
В моем примере я записал все run* в один файл, и там я сгенерировал список всех функций запуска, которые сработали мгновенно — посмотрите на мой Проект Nucleotide, особенно файлы Rules.hs и Nucleotide.hs.

Runs.hs

module Runs where
import Language.Haskell.Extract

listOfRuns = map snd $(functionExtractor "^run")

run1 = …
run2 = …

Main.hs

import Runs

main = do
     putStrLn "please choose a run"
     putStrLn $ show listOfRuns
     let run = runWith $ read $ getLine
     run
  where
    runWith n = listOfRuns !! n

рад быть полезным

person epsilonhalbe    schedule 05.09.2011
comment
Спасибо! это очень полезно, по крайней мере functionExtractor для меня новое. Я провел небольшое исследование и обновил исходный пост. - person claude; 05.09.2011
comment
Это очень похоже на prop_* QuickChekc. Платформа тестирования Haskell HTF, которая собирает все тестовые наборы HUnit/реквизиты QuickCheck в один файл, использует пользовательский препроцессор {-# OPTIONS_GHC -F -pgmF htfpp #-}. Это последнее решение, которое я хочу использовать, но боюсь, что это единственное решение? - person claude; 06.09.2011
comment
я совершенно определенно уверен, что это не единственное решение, но лучшее, что я могу придумать. - person epsilonhalbe; 06.09.2011

Абсолютно ли важно, чтобы разные функции run жили в разных модулях? Если вы можете поместить их все в один модуль, вы можете сделать run функцией Int (или Integer, если хотите).

module AllMyCircuits where
run 0 = {- do blah blah blah -}
run 1 = {- do blah blah blah -}
run 2 = {- do yikes -}

module Main where
import AllMyCircuits
main = readLn >>= run
person Daniel Wagner    schedule 05.09.2011
comment
спасибо, это мое первое решение. Но я должен разделить их, по крайней мере, на небольшие единицы компиляции, чтобы изменение одного run не привело к повторной компиляции других. - person claude; 06.09.2011