1

I'm a Haskell beginner and I am doing a small file for a project that should take the input of interaction data for groups of two people and save it to a list to be output at the end. I have done my best to implement this but it seems like the program hits the "stop" case no matter what is input. Any help or advice would be appreciated.

import Data.List
import Text.Read

main :: IO ()
main = do
    putStrLn "This program is a means to record interactions between individuals during the COVID-19 pandemic."
    putStrLn "Please enter your interactions in this format: 'x interacted with y'"
    inputs <- getUserInputs
    putStr "input: "
    putStrLn ("list sequence " ++ show (inputs))

parseInput :: String -> Maybe String
parseInput input = if input == "stop" then Nothing else (readMaybe input):: Maybe String

getUserInputs :: IO [String]
getUserInputs = do 
    input <- getLine
    case parseInput input of
    Nothing -> return []
    Just aString -> do
        moreinputs <- getUserInputs
        return (aString : moreinputs)
1
  • 6
    readMaybe only succeeds for quoted strings, so if you enter "a" it will work, but not a. You probably want to drop the readMaybe and have simply ... else Just input. Commented Aug 4, 2020 at 1:20

1 Answer 1

1

Show and Read are intended to produce and consume the representation of a value as a Haskell expression. That’s why when you call show on a String, it produces a quoted string:

> show "beans"
"\"beans\""

Therefore Read expects the string to be quoted as well, so readMaybe is always returning Nothing in your code because you’re not supplying quotes:

> readMaybe "beans" :: Maybe String
Nothing

> readMaybe "\"beans\"" :: Maybe String
Just "beans"

Therefore the fix is simple: remove the call to readMaybe and just return the string directly:

parseInput1 :: String -> Maybe String
parseInput1 input = if input == "stop"
  then Nothing
  else Just input

Which, as a matter of style preference, you could also write with guards, pattern matching, or the Maybe monad instead of if:

parseInput2 input
  | input == "stop" = Nothing
  | otherwise = Just input
parseInput3 "stop" = Nothing
parseInput3 input = Just input
import Control.Monad (guard)

parseInput4 input = do
  -- ‘guard’ returns ‘Nothing’,
  -- short-circuiting the ‘do’ block,
  -- if its condition is ‘False’.
  guard (input /= "stop")
  pure input

Read and Show are fine for simple programs, particularly when you’re learning Haskell, but in larger applications it’s helpful to use them mostly for debug input and output and reading input you’ve already validated. Parsing and pretty-printing libraries are preferable for more involved parsing and producing human-readable output, respectively; megaparsec and prettyprinter are good default choices in that area.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.