2011-12-14 18 views
7

Voglio fare qualcosa di simile in Haskell, ma il compilatore non mi lascia.Nome modulo dinamico

Esiste un modo per eseguire questa attività?

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

qual è il problema che si vuole risolvere? Poiché il nome della funzione è noto (ciao), perché non mettere semplicemente le funzioni in una lista '[M1.hello, M2.hello]' e fare qualcosa con quella lista? Immagino che potresti in qualche modo cavartela con TemplateHaskell, ma potrebbe essere eccessivamente complicato. – bzn

risposta

5

non credo che si può citare un prefisso del nome qualificato come quello di modello Haskell, e l'identificatore hello non è nel campo di applicazione, per cui si potrebbe avere a ripiegare alla programmazione con le stringhe.

module ModuleParamsTH where 
import Language.Haskell.TH 

getAll :: String -> [String] -> ExpQ 
getAll valueName moduleNames = 
    listE $ map (varE . mkName . (++ suffix)) moduleNames 
    where suffix = "." ++ valueName 

che può quindi essere utilizzato in questo modo,

{-# LANGUAGE TemplateHaskell #-} 
import ModuleParamsTH 
import qualified ModuleParamsM1 as M1 
import qualified ModuleParamsM2 as M2 

runmodules = $(getAll "hello" ["M1", "M2"]) 

Tuttavia, non vorrei fare tutto questo. Potresti semplicemente scrivere [M1.hello, M2.hello] o usare una classe di tipo per astrarre le implementazioni.

3

I moduli non sono valori in Haskell. Quindi non è possibile. Cosa vuoi ottenere?

8

I moduli di Haskell non sono nemmeno lontanamente entità di prima classe nei modi che questo richiederebbe, temo.

Tuttavia, come commentato da bzn, Template Haskell può essere utilizzato per problemi come questo. Il risultato può essere un po 'goffo, ma se hai davvero bisogno di alcuni hack rapidi per la metaprogrammazione non è una cattiva scelta. Non sono un vero esperto di TH, ma quello che vuoi è piuttosto semplice, con una presa: né "identificatori ambigui" né "nomi di moduli" possono essere catturati o citati in alcun modo, per quanto ne so, quindi tu? Dovremo metterli in stringhe date come argomenti alla funzione TH.

Ecco un rapido e sporco, esempio minimo:

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

È formulato le cose come "l'esecuzione della funzione", che suona più come fare un mucchio di IO azioni, non solo raccogliendo un elenco di cose, così ho aggiunta una variante che sequenzia anche il risultato.

Si noti che, nonostante l'uso di stringhe qui, questo è ancora staticamente tipizzato - se i nomi qualificati non esistono, oi tipi non corrispondono, si otterrà il tempo di compilazione previsto errore proprio come se avessi scritto tutto a mano.

Ecco un breve esempio di utilizzo. Dati i seguenti:

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

Assumendo gli altri moduli ci sono e definiscono test, poi nel GHCi possiamo vedere:

> tests 
Test 1 
Test 2 
Count: 2 
Problemi correlati