[Haskell-cafe] I fell in love with System.Console.Haskeline.getExternalPrint

Brandon Allbery allbery.b at gmail.com
Sun Mar 31 23:13:57 UTC 2019


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.)

On Sun, Mar 31, 2019 at 6:51 PM Mario Lang <mlang at delysid.org> wrote:

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



-- 
brandon s allbery kf8nh
allbery.b at gmail.com
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/haskell-cafe/attachments/20190331/c38597f7/attachment.html>


More information about the Haskell-Cafe mailing list