2010-03-16 22 views
19

Para una herramienta que estoy escribiendo (http://hackage.haskell.org/package/explore) Necesito una forma de leer las definiciones de funciones haskell en tiempo de ejecución, aplicarlas a los valores de mi herramienta y recuperar los resultados de su aplicación .Evaluación de declaraciones/expresiones Haskell usando GHC API

¿Alguien me puede dar un ejemplo muy básico usando GHC (6.10.4 o 6.12.1) API?

ejemplo definición de la función que se lee de un archivo en tiempo de ejecución:

f x = 10**(4/1102*x - 1) 

espera la salida del programa

--mapM_ print $ map f [428, 410, 389] 
3.577165388142748 
3.077536885227335 
2.5821307011665815 

!! ACTUALIZACIÓN !!
He publicado una respuesta rápida pero crea un archivo de objeto en el directorio de ejecución, cualquier consejo para evitar esto y evitar todo el archivo IO es muy bienvenido. También quiero ver una versión que hace todo en la memoria: el usuario proporciona la definición de la función en una GUI, por ejemplo, y la compilación/evaluación no crea ningún archivo objeto.

+0

La API de GHC me dio los primeros ajustes cuando la probé por primera vez en 2006. Estoy realmente interesado en ver qué respuestas obtiene. +1 –

+1

@Norman Ramsey: Acabo de publicar una respuesta adaptada de una publicación de blog de 2008. Sorprendido de ver que 'solo funciona' :) –

+1

Me vienen a la mente dos preguntas: 1) ¿Sería aceptable ejecutar el código interpretado? En ese caso, desea una API en las partes interactivas de ghc, no en el compilador. 2) ¿Necesita ejecutar el código en un entorno restringido? Específicamente, ¿necesita limitar el acceso a cosas como InseguroPerformIO? – MtnViewMark

Respuesta

5

adaptado de: http://www.bluishcoder.co.nz/2008/11/dynamic-compilation-and-loading-of.html

f.hs:

module Func (Func.f) where 

f :: Double -> Double 
f x = 10**(4/1102*x - 1) 

main.hs:

import GHC 
import GHC.Paths 
import DynFlags 
import Unsafe.Coerce 

import Control.Monad 

main :: IO() 
main = 
    defaultErrorHandler defaultDynFlags $ do 
     func <- runGhc (Just libdir) $ do 
     dflags <- getSessionDynFlags 
     setSessionDynFlags dflags 
     target <- guessTarget "f.hs" Nothing 
     addTarget target 
     r <- load LoadAllTargets 
     case r of 
      Failed -> error "Compilation failed" 
      Succeeded -> do 
      m <- findModule (mkModuleName "Func") Nothing 
      setContext [] [m] 
      value <- compileExpr ("Func.f") 
      do let value' = (unsafeCoerce value) :: Double -> Double 
       return value' 
     let f = func 
     mapM_ print $ map f [428, 410, 389] 
     return() 
+2

¡Muchísimas gracias!El setContext ha cambiado en versiones recientes, en su lugar querrás 'setContext [IIModule m]'. – danr

4

Buen trabajo conseguir la API de ir. Puedo contarte un poco sobre cómo funciona el generador de códigos.

GHC usa el ensamblador del sistema para crear un archivo .o. Si no hay una opción disponible para que GHC limpie después de sí mismo, entonces debe presentar una solicitud de función contra la API, usando el rastreador de errores al http://hackage.haskell.org/trac/ghc/newticket?type=feature+request. Para presentar la solicitud, deberá registrar una cuenta.

Utilizando el generador de códigos estándar, no podrá evitar archivos de E/S por completo, simplemente porque GHC delega el trabajo de creación de códigos de objeto reubicables en el ensamblador. Existe un back-end experimental basado en LLVM que podría ser capaz de hacer todo en la memoria, pero me sorprendería si está disponible en algo anterior a 6.13. Sin embargo, podría valer la pena preguntar en la lista de desarrolladores de GHC.

Cuestiones relacionadas