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

Stacking InputT leads to loss of functionality #158

Open
jrp2014 opened this issue Apr 26, 2021 · 2 comments
Open

Stacking InputT leads to loss of functionality #158

jrp2014 opened this issue Apr 26, 2021 · 2 comments

Comments

@jrp2014
Copy link

jrp2014 commented Apr 26, 2021

I have started with a n mtl stack type Forth w a r = ExceptT VMSignal (StateT (VM w a) IO) r and want to use haskeline to provide command line editing to my repl. I've refactored to use type Forth w a r = CME.ExceptT VMSignal (StateT (VM w a) (InputT IO)) r.

And functions which previously ran the stack now have calls like

repl :: (ForthType a, Eq a) => VM w a -> ForthStep w a -> IO ()
repl vm initF = do
  catchSigint vm
  let behaviour = maybe defaultBehavior useFileHandle (inputPort vm)
  (r, vm') <- runInputTBehavior behaviour
                                defaultSettings
                                (runStateT (runExceptT initF) vm)
:

and

fwRefill :: ForthStep w a
fwRefill = do
  vm <- getVm
  case inputPort vm of
    Nothing -> throwError VMNoInput
    Just h  -> do
--      eof <- liftIO (hIsEOF h)
--      when eof (CME.throwError VMEOF)
      trace 2 "REFILL"
      line <- runInputTBehavior (useFileHandle h) defaultSettings
        $ getInputLine "> "
      maybe (throwError VMEOF) (\b -> put (vm { buffer = b })) line
      next

The program works as before (and the > prompt appears. but I can't scroll back into history and the arrow keys still don't work (you get > ^[[A on pushing the up arrow, for example (as before). I don't want to put the InputT on the outside as I'd then have to sprinkle all my code with lifts, which I'd prefer to avoid.

What can I do to get command line editing to function, please?

@judah
Copy link
Collaborator

judah commented Aug 3, 2021

The isue you're having is that you're creating/destroying an InputT context every time you read user input. Ideally you'd only call runInputT once, in your main function. (I believe could still keep InputT at the bottom of your stack as InputT IO as you have now.)

Adapting the example from the Haddocks:
https://hackage.haskell.org/package/haskeline-0.8.1.3/docs/System-Console-Haskeline.html

main :: IO ()
main = runInputT defaultSettings (evalStateT loop 0)

loop :: StateT Int (InputT IO) ()
loop = do
    n <- get
    minput <-  lift $ getInputLine (show n ++ ":")
    case minput of
        Nothing -> return ()
        Just "quit" -> return ()
        Just "q" -> return ()
        Just s -> do
                    lift $ outputStrLn ("line " ++ show n ++ ":" ++ s)
                    modify (+1)
                    loop

@judah
Copy link
Collaborator

judah commented Aug 3, 2021

Another option, if you're having issues with the monad transformer, is the System.Console.Haskeline.IO module:
https://hackage.haskell.org/package/haskeline-0.8.1.3/docs/System-Console-Haskeline-IO.html

That lets you run it in raw IO, at the expense of having to bracket your own initialization/cleanup.

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

2 participants