javascriptfunctional-programmingpurescriptpurely-functionalspago

Purescript: How to read a string from stdin and save it?


I'm quite new to Purescript and I am trying to process some user input (received from stdin) but my best approach is this one:

processInput :: String -> Effect Unit
processInput input = do
  let
    arr = split (Pattern " ") input
    player1 = unsafeIndex arr 0
    player2 = unsafeIndex arr 1
    result = checkGame player1 player2
  log $ "You typed: " <> player1 <> " " <> player2 <> ":" <> show (result)

lineHandler :: Interface -> String -> Effect Unit
lineHandler interface s  = do
  if s == "quit"
    then do
      close interface
    else do
        processInput s
        prompt interface

main :: Effect Unit
main = do
  interface <- createConsoleInterface noCompletion
  setPrompt "> " interface
  setLineHandler (lineHandler interface) interface
  prompt interface

In which I use the Node.ReadLine package to create an interface, ask for input and process it in another method. This is meant for a rock-scissors-paper game and I managed to obtain the result of a single move and log it to the user. But I'm stuck at adding that result to a total outside the lineHandler function.

Is there any other way of obtaining string input from user at main scope (without a lineHandler)? Or is there a way I can define a parameter points which accumulates over the lineHandler executions?

I thought about State but I still don't understand it very well. Thanks in advance


Solution

  • If you want to structure your program as an Interface from Node.ReadLine, you'll have to keep your game state (whatever it may be) in a mutable memory cell, which is represented by the Ref type. You can create such cell with the new function, and then read from and write to it with the read and write functions respectively.

    You'll have to create the memory cell in main and then tunnel it through lineHandler to processInput.

    processInput :: Ref.Ref Int -> String -> Effect Unit
    processInput total input = do
      let
        arr = split (Pattern " ") input
        player1 = unsafePartial $ unsafeIndex arr 0
        player2 = unsafePartial $ unsafeIndex arr 1
        result = checkGame player1 player2
      currentTotal <- Ref.read total  -- Read from the cell
      let newTotal = currentTotal + 42 
      Ref.write newTotal total        -- Write new value to the cell
      log $ "You typed: " <> player1 <> " " <> player2 <> ": " <> show (result) <> ", current total is " <> show newTotal
    
    lineHandler :: Ref.Ref Int -> Interface -> String -> Effect Unit
    lineHandler total interface s  = do
      if s == "quit"
        then do
          close interface
        else do
            processInput total s
            prompt interface
    
    main :: Effect Unit
    main = do
      total <- Ref.new 0  -- Create a new memory cell with initial value of 0
      interface <- createConsoleInterface noCompletion
      setPrompt "> " interface
      setLineHandler (lineHandler total interface) interface
      prompt interface