2011-09-05 18 views
5

He definido muchas funciones (por ejemplo, más de 100), cada una de las cuales realiza un trabajo específico pero con la misma firma. Esto es algo así como:Cómo llamar dinámicamente a una función que se definió en varios módulos en la misma firma

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

lo que quiero hacer es proporcionar el 'correr' real como entrada del usuario, de tal manera que:

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

Actualmente, importación, en todos los módulos, y poner toda la run 's en una lista de [Maybe (IO())], por lo que esto funciona:

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

Pero a medida que crece la n, tengo que mantener continuamente una lista grande.

¿Hay alguna manera de definir la lista grande usando TemplateHaskell, o simplemente cargar el módulo correspondiente según sea necesario en el tiempo de ejecución sin tener que separar cada módulo en diferentes bibliotecas compartidas.


Basado en respuesta epsilonhalbe 's, he hecho un poco de investigación:

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 

Este bloque de código imprime 2 siguientes los resultados de run1 y run2. Si elimino las dos últimas líneas, simplemente imprime 0. Parece que las funciones importadas pero no referenciadas no se extraerán ...

Respuesta

5

Alguna vez tuve un problema similar haskell load module in list quizás esto ayude.

Puede crear una lista de funciones con regexp y elegir una función por la entrada de usuario de esa lista. No sé si tiene que importar todo el "corrimiento" calificado con la mano o si se puede

import R*.hs (run) 

yo prefiero escribir un archivo con run1 = …, run2 = … y generar una lista de todas las carreras y un selector de funciones función que toma una función de una lista de funciones con la misma firma de tipo.

{-# 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 

Atención: Tengo no ejecutar este código esto es sólo una corriente de pensamiento puesto en la sintaxis de Haskell

espero que esto sea útil


Después de editar:
En mi ejemplo escribí todos run* en un archivo y allí generé la lista de todas las funciones de ejecución, que funcionó al instante - echar un vistazo a mi Nucleotide Project especialmente los archivos Rules.hs y 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 

feliz de ser útil

+0

¡Gracias! esto es muy útil, al menos 'functionExtractor' es nuevo para mí. Investigué un poco y actualicé la publicación original. – claude

+0

Esto es bastante parecido al 'prop_ *' de QuickChekc. El marco de prueba de Haskell 'HTF' que recopila todas las pruebas de HUnit/apoyos QuickCheck en un archivo utiliza un preprocesador personalizado' {- # OPTIONS_GHC -F -pgmF htfpp # -} '. Esta es la última solución que quiero usar, pero me temo que esta es la única solución. – claude

+0

estoy absolutamente seguro de que esta no es la única solución, pero es lo mejor que se me ocurre. – epsilonhalbe

1

¿Es absolutamente crítico que las diferentes funciones run viven en diferentes módulos? Si puede ponerlos todos en un módulo, puede hacer que run sea una función de Int (o Integer si lo prefiere).

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 
+0

gracias, esa es mi primera solución. Pero tengo que separarlos al menos en pequeñas unidades de compilación, de modo que cambiar a una 'ejecución 'no compilará a los demás. – claude

Cuestiones relacionadas