haskellhaskell-prelude

"Prelude.read: no parse", own data type


I'm trying to read from file two lists of own data type 'BoardEdge'. When I try to run code I get exception:

"Main.hs: Prelude.read: no parse"

As I suspect I get this on function responsible for validatation of input (validateInput). When I try this function in ghci inserting two BoardEdge 'objects' it works well and gives True.

Can anyone provide me with advice what am I doing wrong and how can I solve the problem?

Data types:

data Field = Empty | Black | Yellow deriving (Eq, Ord, Enum, Show, Read)

data BoardEdge = BoardEdge { colRow :: [[(Field, Int)]]} deriving (Read, Eq, Ord, Show) 

Main.hs

    main :: IO()
    main = do
      args <- getArgs
      input <- loadInput args
      putStrLn "Puzzle input loaded:"
      putStrLn input
      let parsedInput = parseInput input
      if (validateInput parsedInput)
        then putStrLn "Input is valid."
        else error "Input invalid!"

    -- asks for path and reads input file
    loadInput :: [String] -> IO String
    loadInput [] =  getPath >>= readFile where
      getPath = do
        putStrLn "Provide path to puzzle input file:"
        getLine
    loadDefinition (a:_) = readFile a


    -- get valid data from input file
    parseInput :: String -> (B.BoardEdge,B.BoardEdge)
    parseInput d = parseInput' $ lines d where
      parseInput' (columns: rows :_) =
        (read columns, read rows)

Valdiation function in Board.hs imported qualified as B:

    validateInput :: (B.BoardEdge,B.BoardEdge) -> Bool
    validateInput (columns, rows) = rowColEq where
      rowColEq = countBlocks columns == countBlocks rows


    -- function that counts total quantity of colored blocks
    countBlocks :: (B.BoardEdge)-> Int
    countBlocks (B.BoardEdge colRow) = countBlocks' $ concat colRow where
      countBlocks' [] = 0
      countBlocks' (x:xs) = snd x + countBlocks' xs

And my input files are like this:

    [[(Black,2),(Yellow,2),(Black,1)],[(Black,2),(Yellow,1),(Black,3)]]
    [[(Black,5)],[(Black,2),(Black,1)],[(Black,2),(Black,2)],[(Black,1),(Black,2)]]

Solution

  • Gluing together your own code snippets and Fyodor's comment:

    Prelude> data Field = Empty | Black | Yellow deriving (Eq, Ord, Enum, Show, Read)
    Prelude> data BoardEdge = BoardEdge { colRow :: [[(Field, Int)]]} deriving (Read, Eq, Ord, Show)
    Prelude> let edge1 = BoardEdge [[(Black,2),(Yellow,2),(Black,1)],[(Black,2),(Yellow,1),(Black,3)]]
    Prelude> show edge1
    "BoardEdge {colRow = [[(Black,2),(Yellow,2),(Black,1)],[(Black,2),(Yellow,1),(Black,3)]]}"
    Prelude> let correctInput = it -- ^^ the above
    

    So now we know what read expects, which is what show produced. How does this compare with what you used as the input?

    Prelude> let myInput =     "[[(Black,2),(Yellow,2),(Black,1)],[(Black,2),(Yellow,1),(Black,3)]]"
    Prelude> correctInput == myInput
    False
    

    Or less snarky: If you want default read instances to parse your input then your input must be correct Haskell code with data constructors and all. In this case using BoardEdge was needed.