Skip to content

Instantly share code, notes, and snippets.

@luochen1990
Last active November 27, 2021 15:44
Show Gist options
  • Save luochen1990/ad01e5cfbd43c714a66ccc1eb5e55bff to your computer and use it in GitHub Desktop.
Save luochen1990/ad01e5cfbd43c714a66ccc1eb5e55bff to your computer and use it in GitHub Desktop.
Haskell eval & repl implemented via hint & conduit
#!/usr/bin/env nix-shell
#! nix-shell -p "haskellPackages.ghcWithPackages (p: with p; [conduit conduit-extra bytestring text hint])"
#! nix-shell -i "ghci -ignore-dot-ghci -fdefer-type-errors -XTypeApplications"
{-# language ScopedTypeVariables, TypeApplications, PartialTypeSignatures #-}
{-# language OverloadedStrings #-}
import Conduit
import Data.Conduit
import Data.ByteString (ByteString)
import Data.Text (Text, pack, unpack)
import qualified Data.Conduit.Text as CT
import Data.Typeable (Typeable)
import qualified Language.Haskell.Interpreter as Hint
-- * eval
eval :: forall t. Typeable t => String -> IO t
eval s = do
mr <- Hint.runInterpreter $ do
Hint.setImports ["Prelude"]
Hint.interpret s (Hint.as :: t)
case mr of
Left err -> error (show err)
Right r -> pure r
evalS :: String -> IO String
evalS s = eval @String ("show (" ++ s ++ ")")
-- * Proc & LinedProc
type CliArg = [Text]
type Proc = ConduitT ByteString ByteString IO Int
type Command = CliArg -> Proc
type Line = Text -- ^ line is text without newline
type LinedProc = ConduitT Line Line IO Int
-- * run & runLined
unlined :: LinedProc -> Proc
unlined proc = CT.decode CT.utf8 .| CT.lines .| mapOutput (<> "\n") (proc `fuseUpstream` CT.encode CT.utf8)
run :: Proc -> IO Int
run proc = runConduit (stdinC .| proc `fuseUpstream` stdoutC)
runLined :: LinedProc -> IO Int
runLined proc = run (unlined proc)
-- * echoLine & repl
echoLine :: LinedProc
echoLine = do
ml <- await
case ml of
Just l -> if l == "exit" then pure 0 else yield l >> echoLine
Nothing -> pure 0
repl :: LinedProc
repl = echoLine `fuseUpstream` mapMC (\l -> (pack . show) <$> evalS (unpack l))
-- * main
main :: IO Int
main = runLined repl
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment