<div dir="ltr">You might consider that ghci is just a client of ghc-api that's built into ghc for convenience; see the ghci-ng package on hackage, which is a standalone version used to experiment with new ghci features. ghci itself has a separate interpreter, in other words. (Note also -fexternal-interpreter, which relies on this to move the backend to a different process or even different host for cross-platform work; you might want to look into customization at that level.)</div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Sun, Mar 31, 2019 at 6:51 PM Mario Lang <<a href="mailto:mlang@delysid.org">mlang@delysid.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Hi.<br>
<br>
Since I discovered getExternalPrint, I found a ton of use cases for it.<br>
In particular, it makes it possible to write background threads that<br>
report stuff to the console without disturbing the prompt.<br>
<br>
I ended up writing a sort of uGHCi with the help of hint and the<br>
unreleased master branch of haskeline[1] to make externalPrint available<br>
from within the interpreter.  Combined with Shh, this opens the door for<br>
a lot of useful functionality.  Here is a simplified example based<br>
on shell programming with the help of Shh:<br>
<br>
  % let watch r p = forkIO . forever $ printProc p >> readIORef r >>= OS.sleep<br>
  % delay <- newIORef 10<br>
  % clock <- watch delay OS.date<br>
  Sat Mar  2 21:32:28 CET 2019<br>
  Sat Mar  2 21:32:38 CET 2019<br>
  % writeIORef delay 5<br>
  Sat Mar  2 21:32:48 CET 2019<br>
  Sat Mar  2 21:32:53 CET 2019<br>
  Sat Mar  2 21:32:58 CET 2019<br>
  Sat Mar  2 21:33:03 CET 2019<br>
  % killThread clock<br>
<br>
printProc uses externalPrint from haskeline to print the output of a<br>
shell command to the console without disturbing the prompt.<br>
The OS module in this example simply exports all executables as haskell<br>
functions, thanks to the TH magic from Shh.<br>
<br>
I am relying on a pretty crude hack to make this work:<br>
<br>
  (rFd, wFd) <- liftIO createPipe<br>
  eprint <- getExternalPrint  -- from haskeline<br>
  liftIO . forkIO . forever $ do<br>
    (s, bc) <- fdRead rFd 1024<br>
    eprint s<br>
  -- ...<br>
  -- define a function in the interpreter using hint<br>
  runStmt $ "let externalPrint s = fdWrite (read " <> show (show wFd) <> ") s >> pure ()"<br>
<br>
This hack is basically the whole magic of my own hand-rolled uGHCi.<br>
<br>
I'd love to not reinvent the wheel there, and just be able to use<br>
standard GHCi to make use of externalPrint.<br>
<br>
Question is, would a similar thing be possible to implement in GHCi<br>
directly, and if so, what would be required to make this work?<br>
I am likely far too much a rooky to get this working on my own, so I am<br>
asking for help.  What steps should I follow to eventually achieve my<br>
goal?  I guess submitting a feature request would be a start.<br>
However, I want progress, so I am wondering:<br>
<br>
* The pipe trick is likely too hacky for GHCi.  Are there any other<br>
  portable alternatives for getting data from within the interpreter to<br>
  the haskell process running it?<br>
* Or is there a way to serialize an IO action into the interpreter that I've missed?<br>
<br>
The problem here is the boundary between the process that runs<br>
the interpreter, and the interpreter itself.  I am a bit whacky on<br>
terminology here, but as I see it, getExternalPrint returns a function that<br>
has internal state.  So it isn't really possible to make such a function<br>
available from within the interpreter.  Hence, the pipe hack above,<br>
which just sends the *argument* to externalPrint from the interpreter to<br>
the process running it.<br>
<br>
Any insights that might help me make that available in standard<br>
GHCi?  I really think this is a pretty unique feature that would enable<br>
all sorts of interesting interactive code.<br>
<br>
[1] Haskeline < 0.8.0 doesn't allow to combine IntterpreterT from hint<br>
with InputT because of the way exceptions are done.  The master branch<br>
of haskeline fixes that, so finally you can have a transformer stack<br>
that combines both, allowing for pretty simple interactive haskell<br>
interpreters with readline functionality.  Thanks for that!<br>
<br>
-- <br>
CYa,<br>
  ⡍⠁⠗⠊⠕<br>
_______________________________________________<br>
Haskell-Cafe mailing list<br>
To (un)subscribe, modify options or view archives go to:<br>
<a href="http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe" rel="noreferrer" target="_blank">http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe</a><br>
Only members subscribed via the mailman list are allowed to post.</blockquote></div><br clear="all"><div><br></div>-- <br><div dir="ltr" class="gmail_signature"><div dir="ltr"><div><div dir="ltr"><div>brandon s allbery kf8nh</div><div><a href="mailto:allbery.b@gmail.com" target="_blank">allbery.b@gmail.com</a></div></div></div></div></div>