2011-04-07 13 views
9

En realidad tengo alguna fórmula como "x + y", que es un String. Logré reemplazar la variable x/y con valores específicos como "1.2", que todavía es String tipo. Ahora tengo una expresión como "1 + 2".Haskell: cómo evaluar una cadena como "1 + 2"

Así que el problema es cómo evaluar una expresión de un tipo de cadena y obtener el resultado.

ps: Quiero algo así como read, que puede convertir directamente la expresión de cadena completa en lugar de manejar el operador (+/-, etc.) caso por caso. ¿Es eso posible?

+1

Por supuesto, es posible. Pero creo que deberías usar una mejor representación para las expresiones.Una pista puede ser su frase "convertir toda la expresión de cadena". La pregunta es: ¿convertir a ** qué **? – Ingo

+0

Creo que yoz quiere evaluarlo, y está usando el término convertir como 'convertir a un resultado'. – mdm

+0

@mdm, seguro, por eso estoy pidiendo: hacerle comprender que la conversión y la evaluación son cosas diferentes. O evalúa la cadena directamente (que ya rechazó), o convierte (¿a qué? Esta es la pregunta clave) y luego evalúa eso. – Ingo

Respuesta

19

Su pregunta deja mucho espacio para la interpretación. Supongo que no está acostumbrado a construir una línea completa de lexings, análisis sintácticos, tal vez verificación de tipos y evaluación. La respuesta larga implicaría definir qué idioma desea evaluar (solo enteros con '+', quizás todos los racionales con '+', '-' '* *', '/', o incluso un lenguaje más grande?) Y realice cada uno de los pasos anteriores para ese idioma.

La respuesta corta es: para evaluar expresiones Haskell, que incluye los operadores matemáticos básicos que probablemente estamos hablando, sólo tiene que utilizar el paquete de "pista":

$ cabal install hint 
... 
$ ghci 
> import Language.Haskell.Interpreter 
> runInterpreter $ setImports ["Prelude"] >> eval "3 + 5" 
Right "8" 

Yay!

+0

Estaba tratando de encontrar una manera de evaluar una expresión String sin análisis léxico, definiciones gramaticales, etc. C# puede lograr esto compilando código en tiempo de ejecución. Entonces realmente me preguntaba si hay algo similar en Haskell. Tu respuesta es exactamente lo que necesito. Muchas gracias ~ – yoz

+0

@yoz Me alegro de poder ayudar. Obviamente, usted puede leer los [documentos de eglefino usted mismo] (http://hackage.haskell.org/packages/archive/hint/0.3.3.2/doc/html/Language-Haskell- Interpreter.html), pero muy rápidamente el 'interpretar 'función le dará un resultado de tipo polimórfico (no una representación de cadena), que podría ser aún mejor dependiendo de sus necesidades. Feliz piratería. –

+0

¿Alguna manera de hacer esto con Haskell estándar, sin instalar 'hint'? – vikingsteve

5

Puede valer la pena leer la sección Parsec de Real World Haskell. Podrías analizarlo en un árbol de expresiones y luego sustituirlo por los valores. Al usar Parsec crearías un árbol de expresiones usando tipos (muy aproximadamente, estoy seguro de que cometí algunos errores que editaré en arreglos) ¡cuando y como la gente los señale!) como la siguiente.

data Op = Plus | Minus 
data Term = Variable String 
      | Value Int 
data Expression = Expr Expression Op Expression 
       | Term 

Entonces 1 + 2 sería (Expr (Variable "x") Plus (Variable "y")) y se podía aplicar las sustituciones apropiadas.

Para obtener el resultado, supongo que podría corregir una función simple evaluate :: Map String Int -> Expression -> Either ErrorMessage Int que aplicaría los enlaces en el mapa y luego calcular el resultado si es posible.

+1

Creo que @yoz esperaba algo más de una función incorporada 'eval :: String -> Double'. A * little * more haskellish sería tal vez 'eval :: String -> O ErrorMessage Double'. Sin embargo, como la mayoría ha señalado, las expresiones representadas como cadenas son malas. Mejor usar un árbol de sintaxis como Jeff mostró. – Tarrasch

2

Bueno, he estado golpeando mi cabeza contra hint pero me doy por vencido por el momento. Sé que la sugerencia puede hacer esto, pero no estoy seguro de cómo. [editar] Consulte la respuesta de TomMD para saber cómo configurar las importaciones para la pista. [/ editar]

import Language.Haskell.Interpreter (eval, runInterpreter, Interpreter, InterpreterError) 

main = do let resIO = eval "3" :: Interpreter String 
      res <- runInterpreter resIO 
      print res 

Este carecer de interés produce Right "3" como el resultado. Probé las siguientes variantes, pero se encontró con errores desconcertantes:

... eval "3 + 3" .... 
-- yields -- 
Left (WontCompile [GhcError (errMsg = "Not in scope: `+'"]) 

El operador + no está en el ámbito ??? wtf ...

import Language.Haskell.Interpreter (interpret, as, runInterpreter, Interpreter) 

main = do let resIO = interpret "3" (as :: Int) :: Interpreter Int 
      res <- runInterpreter resIO 
      print res 
-- yields -- 
Left (WontCompile [GhcError (errMsg = "Not in scope: type constructor or class 'Int'")]) 

La clase Int no está en el ámbito ??? ugh ...

Invito a los que tienen más conocimientos que yo a exponer los detalles más finos de la pista.

+4

Necesita 'setImports', ver mi respuesta. –

Cuestiones relacionadas