2

I'm new to Haskell as well as Stack. This would be one of my first few programs in Haskell. Hence, unable to make it work correctly so far.

  1. With the help of a small Haskell program, a JSON file (a short summary of statistics data from a website - in nested JSON format) was obtained. I got that inside 'App' folder of that stack project.

  2. In the next program/stack-project, we try to parse the data.json (obtained in the previous program) and get only certain portion of that statistics displayed/printed in ghci - in a list format (with the help of forM_ [decoded-JSON's-certain-portion-of-data-in-list-format] (print . name)). Since the 'decode-JSON' function (from Data.Aseon) would produce results in Maybe format, we also do pattern-matching to display 'Error - loading data' in case the result is nothing; And, do forM_ when there is Just data.

  3. My issue is that - Code compiles; But, says 'Error - loading failed' even when I had placed the data.json inside this particular stack project's folder.

  • have added 'import System.IO' in Main module.
  • have added "Data-files: (/n)-data.json" inside package.yaml - at the top, right below the 'extra-source-files' details.

I didn't make any manual update inside cabal file. Stack wouldn't let me do any manual change in cabal file and asks me to delete either cabal or package.yaml. There are no such errors/warnings thrown by stack, when package.yaml is updated with the details of 'Dependencies and Extensions' details,etc. Hence, I updated this data.json info in package.yaml.

(Though I am not sure which is the right location inside stack-proj-folder, where the input data ought to be placed.

  • I tried placing it as one of the elements in the root folder of the project, along with package.yaml, cabal file and stack.yaml etc;

  • I also placed a copy of data.json file - inside 'app' folder - along with Main.hs file (as that's where the output what placed by stack in the previous program. Hence, assumed stack might look consider this folder for input/output files, though I'm not sure and it doesn't seem to work as expected);

  • I also made one additional folder named 'data' (just like src, app and test) , and have placed a copy of data.json file inside that. Though I haven't given any description inside package.yaml for this new 'data' folder, as I wasn't sure of the right way to do it)

But, irrespective of all these places I have tried placing the input data.json file - for stack to access and read, it doesn't seem to work so. The compiled code always returns 'Error loading data' - indicating the decodeJSON function returned nothing/no-data - even though the file/data-format is valid. (It was not manually prepared file - where the error could occur due to manual formatting; It was just a system produced JSON file data from a website. And, it has valid data for decoding)

I am attaching

  • package.yaml update
  • data.json file's data
  • Main module code here for reference.

At the top of packagae.yaml :

   extra-source-files:
    - README.md
    - ChangeLog.md

   data-files:
    - data.json

The data in the file named "data.json" :

    {"metadata":{"resultset":{"offset":1,"count":11,"limit":25}},"results":[{"uid":"gov.noaa.ncdc:C00861","mindate":"1763-01-01","maxdate":"2021-07-02","name":"Daily Summaries","datacoverage":1,"id":"GHCND"},{"uid":"gov.noaa.ncdc:C00946","mindate":"1763-01-01","maxdate":"2021-06-01","name":"Global Summary of the Month","datacoverage":1,"id":"GSOM"},{"uid":"gov.noaa.ncdc:C00947","mindate":"1763-01-01","maxdate":"2021-01-01","name":"Global Summary of the Year","datacoverage":1,"id":"GSOY"},{"uid":"gov.noaa.ncdc:C00345","mindate":"1991-06-05","maxdate":"2021-07-02","name":"Weather Radar (Level II)","datacoverage":0.95,"id":"NEXRAD2"},{"uid":"gov.noaa.ncdc:C00708","mindate":"1994-05-20","maxdate":"2021-07-02","name":"Weather Radar (Level III)","datacoverage":0.95,"id":"NEXRAD3"},{"uid":"gov.noaa.ncdc:C00821","mindate":"2010-01-01","maxdate":"2010-01-01","name":"Normals Annual/Seasonal","datacoverage":1,"id":"NORMAL_ANN"},{"uid":"gov.noaa.ncdc:C00823","mindate":"2010-01-01","maxdate":"2010-12-31","name":"Normals Daily","datacoverage":1,"id":"NORMAL_DLY"},{"uid":"gov.noaa.ncdc:C00824","mindate":"2010-01-01","maxdate":"2010-12-31","name":"Normals Hourly","datacoverage":1,"id":"NORMAL_HLY"},{"uid":"gov.noaa.ncdc:C00822","mindate":"2010-01-01","maxdate":"2010-12-01","name":"Normals Monthly","datacoverage":1,"id":"NORMAL_MLY"},{"uid":"gov.noaa.ncdc:C00505","mindate":"1970-05-12","maxdate":"2014-01-01","name":"Precipitation 15 Minute","datacoverage":0.25,"id":"PRECIP_15"},{"uid":"gov.noaa.ncdc:C00313","mindate":"1900-01-01","maxdate":"2014-01-01","name":"Precipitation Hourly","datacoverage":1,"id":"PRECIP_HLY"}]}

Code :

module Main where

import Data.Aeson
import qualified Data.Text as T
import qualified Data.ByteString.Lazy as B
import qualified Data.ByteString.Lazy.Char8 as BC
import GHC.Generics
import Control.Monad
import Control.Applicative
import System.IO

Data Type declaration for the data inside data.json :

    data NOAAResult = NOAAResult
                { uid :: T.Text
                , mindate :: T.Text
                , maxdate :: T.Text
                , name :: T.Text
                , datacoverage :: Int
                , resultId :: T.Text
                } deriving Show

    instance FromJSON NOAAResult where
        parseJSON (Object v) =
                        NOAAResult <$> v .: "uid"
                            <*> v .: "mindate"
                            <*> v .: "maxdate"
                            <*> v .: "name"
                            <*> v .: "datacoverage"
                            <*> v .: "id"                  

    data Resultset = Resultset
                { offset :: Int
                , count :: Int
                , limit :: Int
                } deriving (Show,Generic)
              
    instance FromJSON Resultset
              
    data Metadata = Metadata
                {
                resultset :: Resultset
                } deriving (Show,Generic)
              
    instance FromJSON Metadata

    data NOAAResponse = NOAAResponse
                { metadata :: Metadata
                , results :: [NOAAResult]
                } deriving (Show,Generic)
              
    instance FromJSON NOAAResponse

IO actions :

    printResults :: Maybe [NOAAResult] -> IO ()
    printResults Nothing = print "error loading data"
    printResults (Just results) = do
    forM_ results (print . name)


    main :: IO ()
    main = do
     jsonData <- B.readFile "data.json"
     let noaaResponse = decode jsonData :: Maybe NOAAResponse
     let noaaResults = results <$> noaaResponse
     printResults noaaResults
  • Would be helpful to know the right place and right procedure to place input data file in haskell-stack.

  • Also, after placing the data file in the respective folder/path, what updates need to be made in config files (like cabal (or) package.yaml) and in the code (like import System.IO) - so that the haskell program would have no issue in identifying the input data file from the stack-project folder and process it fine. ( As in my case, it gives 'Error loading data' message - even when the data.json input file is placed inside stack-proj folder. Hence, I assume, I am missing something to do it right)

Requesting for guidance/help.

Thank you.

1 Answer 1

0

If I run your example as a hard-coded string with eitherDecode I get the following:

Left "Error in $.results[3].datacoverage: parsing Int failed, value is either floating or will cause over or underflow 0.95"

So, it seems that the type of datacoverage should be Double not Int:

data NOAAResult = NOAAResult
            { uid :: T.Text
            , mindate :: T.Text
            , maxdate :: T.Text
            , name :: T.Text
            , datacoverage :: Double
            , resultId :: T.Text
            } deriving Show

Does that help?

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

4 Comments

Also, should we manually place the input file inside the current stack project folder? Or, is there a way to make haskell lookup for input data from external folders (other stack project modules). In that case, what would be the procedure to add that data in haskell code as well as in config files (.yaml/cabal/etc) Thank you.
@user16400316 I think the nicest way in this case is to let the user input the location of the data.json file that they want to summarize. If you really want to bundle it with your package then you can use data-files, see the full documentation here: cabal.readthedocs.io/en/3.4/….
Just one more qn/help needed. When I tried eitherDecode, my error message was not as descriptive as yours. I just got parse error on input "'' ` . That's it. What could be the reason. Asking because getting the description of error might make it easier to identify the issue quickly. I remember trying eitherDecode before too. But, it was similar generic error message - without any description on the exact error location/detail. What could be the reason, if you could guess. Thank you.
Got how to get detailed error now. Thank you anyway. Sorry for the multiple questions.

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.