Reputation: 609
I have a little toy semantics for natural language, with words like:
ran :: String -> Bool
ran = (`elem` ["Bart", "Homer", "Marge"])
and:
bart :: String
bart = "Bart"
So for example, I can have (ran bart) :: Bool
, and so on.
I want to write a parser which, for example takes the string "Bart ran"
and returns True
. I'd probably use Parsec for this.
However, the problem is being able to call functions via strings. E.g. getting from "ran"
to the function ran
. For this, I thought Language.Haskell.Interpreter
's interpret
function might be appropriate.
So my questions are:
Is this a sensible way to do what I want to do?
If so, why doesn't the following work, entered into GHCi, given a module called Grammar.hs
in the same directory with ran
defined as above:
let a = runInterpreter $ do
loadModules ["Grammar"]
setImports ["Prelude"]
interpret "ran" (as :: String -> Bool)
let b = do
x <- a
return $ x <*> pure "John"
b
I get the error:
"Left (WontCompile [GhcError {errMsg = "<interactive>:2:1:\n Not in scope: \8216ran\8217\n Perhaps you meant \8216tan\8217 (imported from Prelude)"}])"
which suggests that the import isn't working, and indeed, if I try something similar with a Prelude function, everything works.
let
):No instance for
MonadIO m0
arising from a use ofrunInterpreter
Upvotes: 1
Views: 68
Reputation: 27626
As for #2, you need to add "Grammar"
to the setImports
list as well:
runInterpreter $ do
loadModules ["HintDefs"]
setImports ["Prelude", "HintDefs"]
interpret "ran" (as :: String -> Bool)
As for #3, it is because runInterpreter
is monomorphic in the choice of monad to run it in:
runInterpreter :: (MonadIO m, MonadMask m) => InterpreterT m a -> m (Either InterpreterError a)
So you'll need to choose a particular m
by running it in e.g. IO
:
main :: IO ()
main = do
ran <- runInterpreter $ do
loadModules ["HintDefs"]
setImports ["Prelude", "HintDefs"]
interpret "ran" (as :: String -> Bool)
print $ ran <*> pure "John"
Now, as for #1, I am not convinced you need something as stupidly powerful as HInt here. You could just maintain a dictionary of String -> Bool
functions keyed by a String
key, something simple like a Map String (String -> Bool)
, and then use that to look up ran
etc.
Upvotes: 2