Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

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?

like image 382
asg0451 Avatar asked Jun 03 '14 23:06

asg0451


People also ask

Is Haskell hard to read?

Haskell is simply much more expressive and capable of abstracting over many more things (perhaps this is why you say it is hard to read). The Haskell ecosystem is also constantly evolving and solving more and more real world problems, often problems that have not been solved in other languages.

What is a function in Haskell?

Functions play a major role in Haskell, as it is a functional programming language. Like other languages, Haskell does have its own functional definition and declaration. Function declaration consists of the function name and its argument list along with its output.

What does B mean in Haskell?

In b Bool , b stands for a parametrized type that takes one type parameter (in Haskell parlance, b is a type constructor of kind * -> * ), such as Maybe , IO or [] . So a function of type a -> b Bool could for example take an Int and produce a Maybe Bool , IO Bool , [Bool] etc.


2 Answers

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.

like image 155
mariop Avatar answered Oct 03 '22 13:10

mariop


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.

like image 33
J. Abrahamson Avatar answered Oct 03 '22 13:10

J. Abrahamson