Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

call eval inside of REPL prompt to execute string? #56

Open
subes opened this issue Oct 28, 2024 · 1 comment
Open

call eval inside of REPL prompt to execute string? #56

subes opened this issue Oct 28, 2024 · 1 comment

Comments

@subes
Copy link

subes commented Oct 28, 2024

Hi,

I am building an integration for frege here: https://github.com/invesdwin/invesdwin-scripting/tree/main/invesdwin-scripting-parent/invesdwin-scripting-haskell/invesdwin-scripting-haskell-runtime-frege/src/main/java/de/invesdwin/scripting/haskell/runtime/frege

The current integration works by running the FregeREPL in a separate process and communicating with it to provide Frege scripting integration from Java. This is because I could not figure out how to parse, eval, then extract results from the Frege API in Java because of all those complex generated java classes. Some old example I found somewhere to extract some results was outdated and did not work anymore. So the REPL it is.

Currently I am working on bidirectional communication between Java <-> Frege (file based because I can make this functional easily without global variables for a socket connection) . For that one can call something like callback ["someJavaFunctionStr" param1 param2 ... paramN] inside a Frege script. Java then produces another Frege expression that is then supposed to be parsed by Frege and evaluated. Though I did not find a way to call eval "someExpressionStr" inside the repl from within a function? I need something like the hint interpreter: https://stackoverflow.com/questions/2141148/best-way-to-call-haskell-functions-from-within-java/2144410#2144410 (though not yet tested for the GHCI integration). Maybe one can just import the FregeRepl and call eval to parse and execute a string?

print console (cmd@(Eval line)) (CodeInfo sourceRepr g msgs) env = case sourceRepr of

Another option would be to return a json string from java to frege with additional type information to convert the values into frege values/lists/matrices based on the type. Though with that one would lose the capability to return arbitrary expressions from callback functions (which could be simulated though by running a second frege repl). Though this would be the most unnecessary complex and convoluted way to do this. No other language required workarounds like this (already done in the same repo for julia, python, R, matlab, ...).

@subes
Copy link
Author

subes commented Oct 29, 2024

I got 4 versions running that interpret a string into frege code, though dunno how to extract the results:

This seems to use its own nested repl env, not the one where I am typing these commands. I don't know how to return the result of "1+1". Trying "asdf = 1+1" and typing "asdf" in the outer repl does not seem to share the state. I don't think it will be possible to access/modify the outer repl state because of the immutable nature of Frege/Haskell. So the only way would be to evaluate and extract the result of "1+1" which I don't know how to do.

import frege.repl.FregeRepl
typeCmd = Type "1+1"
--> value typeCmd :: Command
Repl.run (eval typeCmd)
--> ReplEnv -> IO (ReplResult,ReplEnv)

Here we are a bit lower level inside the repl, but I can not access or pass the outer repl env and the immutability of Frege/Haskell would not allow to modify the outer repl state within a function call anyhow. So "asdf = 1+1" will not work as well.
At least here we get a direct ReplResult instead of an IO that requires additional evaluation.

import frege.repl.FregeRepl
typeCmd = Type "1+1"
--> value typeCmd :: Command
eval typeCmd
--> Repl ReplResult

Or we go another layer down by accessing the FregeInterpreter directly. Though again I don't know how to force evaluation or how to return the nomad in a way so that the outer callback function can return it as a result.

import Interpreter.FregeInterpreter
Interpreter.run (interpret "1+1")
--> InterpreterConfig -> MutableIO InterpreterClassLoader -> IO (InterpreterResult,MutableIO InterpreterClassLoader)

Or we use the FregeScriptEngine (maybe most promising):

import frege.scriptengine.FregeScriptEngine

eval "1+1"
MutableIO ScriptContext -> IO (Maybe Object)

evalResult "1+1"
FregeInterpreter.InterpreterConfig -> MutableIO ScriptContext -> FregeInterpreter.InterpreterResult -> MutableIO FregeInterpreter.InterpreterClassLoader -> IO (Maybe Object)

Though I guess I am missing the ScriptContext and a way to invoke the returned IO. Or do I have to create a new ScriptEngine and invoke the eval there instead of trying the top-scope eval function? Sadly there no ScriptEngine.new or ScriptContext.new

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant