1

Haskell newbie here and also first time asking a question here, apologies in advance for anything I may have missed anything.

Im writing a repl function that takes user input, adds the input to a list and uses haskeline to tab complete user input with previously typed words.

So far I can only complete words with a static list defined before run time.

1- How would I add the input word to the list in repl (SOLVED...?)

2- How would I enable the searchFunc to query the list in the repl loop?

My current code:

import Data.List
import System.Console.Haskeline

-- main method
main :: IO ()
main = runInputT mySettings (repl [])

repl :: [String] -> InputT IO ()
repl list =
    do
        minput <- getInputLine "> "
        case minput of
            Nothing     ->  do
                            outputStrLn "Error"
                            repl list

            Just input  ->
                           do
                           outputStrLn "Successfully added input to list"
                           -- < 1- add input word to list ... is this correct?>
                           repl (input:list)

mySettings :: Settings IO
mySettings = Settings { historyFile = Just "myhist",
                        complete = completeWord Nothing " \t" $ return . searchFunc,
                        autoAddHistory = True
                      }


searchFunc :: String -> [Completion]
-- < 2- complete word using list of words from repl>
searchFunc str = map simpleCompletion $ filter (str `isPrefixOf`) listFromRepl

Any help is appreciated, thanks in advance.

Will Ness
  • 70,110
  • 9
  • 98
  • 181
shadow123
  • 11
  • 2
  • 1- `do { outputStrLn "Successfully added input to list" ; repl (input:list) }` ? – Will Ness Apr 07 '21 at 12:58
  • @WillNess thanks! that solves problem 1 – shadow123 Apr 07 '21 at 13:01
  • better ask whether it is the correct solution. :) maybe you must also update some internals or what not. (I don't know.) I've edited. – Will Ness Apr 07 '21 at 13:04
  • sorry i didnt understand, wdu mean? – shadow123 Apr 07 '21 at 13:06
  • 1
    Welcome to Stack Overflow! [The most recent Haskeline question before yours](https://stackoverflow.com/q/66859656/246886) asks about an equivalent task. [My answer](https://stackoverflow.com/a/66860484/246886) describes the use of `StateT [String] IO` or `ReaderT (IORef [String]) IO` instead of just `IO` within `InputT` to retain the list and make it available to the completion function. Your current `[String] -> InputT IO ()` (= `ReaderT [String] (InputT IO) ()`) can’t do this—modifications are local to `repl`. If that solves your problem, we can close this question as a duplicate. – Jon Purdy Apr 07 '21 at 22:38
  • Hi thanks for the reply @JonPurdy, I am a little confused with this line in your solution ```lift $ modify (ipt :)```, how can I directly access my list within the loop, for eg if i wanted to add an element to it like so ```(ipt : list)``` or pass it to some other function like so ```someFunc list```. Excuse me for my naivety. – shadow123 Apr 08 '21 at 09:50
  • @shadow123: That line uses [`lift`](https://hackage.haskell.org/package/transformers-0.5.6.2/docs/Control-Monad-Trans-Class.html#v:lift) to run a `StateT` action in the combined `InputT`+`StateT`. `modify` updates the state with a function; to read the state, use [`get`](https://hackage.haskell.org/package/transformers-0.5.6.2/docs/Control-Monad-Trans-State-Lazy.html#v:get), e.g. `inputs <- lift get`, or its cousin `gets`. Look for tutorials on `State`/`StateT` for a more detailed explanation than I can offer here. And in general, prefer opening a new question for more detailed follow-ups. – Jon Purdy Apr 08 '21 at 17:57
  • @JonPurdy thank you, much appreciated! – shadow123 Apr 08 '21 at 19:36

0 Answers0