asg0451
asg0451

Reputation: 503

Is it possible to 'read' a function in Haskell?

new user, semi-noobie Haskell programmer here. I've been looking through 'Write yourself a Scheme in 48 hours' and it occurred to me that, though it would be extremely unsafe in practice, it would be interesting to see if a Haskell program could 'read' a function.

For example, read "+" :: Num a => a -> a -> a -- (that is the type of (+) )

The above example did not work, however. Any ideas? I know this is a really dumb thing to do in practice, but it would be really cool if it were possible, right?

Upvotes: 9

Views: 400

Answers (2)

J. Abrahamson
J. Abrahamson

Reputation: 74374

The general answer is that, no, you cannot. Functions are very "opaque" in Haskell generally—the only way you can analyze them is to apply arguments to them (or use typeclasses to pull information out of the type, but that's different).

This means it's very difficult to create a dynamic function in any sort of specialized or simplified way. The best you can do is embed a parser, interpreter, and serialization/deserialization mechanism to another language and then parse strings of that language and execute them in the interpreter.

Of course, if your interpreted language is just Haskell (such as what you get using the hint package) then you can do what you're looking for.

Upvotes: 2

mariop
mariop

Reputation: 3226

Haskell is a static and compiled language and you can interpret a string as a function by using Language.Haskell.Interpreter.

A minimal example that reads a binary function with type Int -> Int -> Int is:

import Language.Haskell.Interpreter
import System.Environment (getArgs)

main :: IO ()
main = do
  args <- getArgs
  -- check that head args exists!
  errorOrF <- runInterpreter $ do
    setImports ["Prelude"]
    interpret (head args) (as::Int -> Int -> Int)
  case errorOrF of
    Left errs -> print errs
    Right f   -> print $ f 1 2

You can call this program in this way (here I assume the filename with the code is test.hs):

> ghc test.hs
...
> ./test "\\x y -> x + y"
3

The core of the program is runInterpreter, that is where the interpreter interprets the String. We first add the Prelude module to the context with setImports to make available, for example, the + function. Then we call interpret to interpret the first argument as a function and we use as Int -> Int -> Int to enforce the type. The result of runInterpreter is a Either InterpretError a where a is your type. If the result is Left then you have an error, else you have your function or value. Once you have extracted it from Right, you can use it as you use a Haskell function. See f 1 2 above, for example.

If you want a more complete example you can check haskell-awk, that is my and gelisam project to implement a awk-like command line utility that use Haskell code instead of AWK code. We use Language.Haskell.Interpreter to interpret the user function.

Upvotes: 11

Related Questions