+1 (315) 557-6473 

Simple Query Language in Haskell, and Provide Routines for Dealing with CSV Files in Haskell Assignment Solution.


Instructions

Objective
Write a haskell assignment program, and provide routines for dealing with CSV files in haskell.

Requirements and Specifications

{------------------------------------------------------------------------}
{- Part 1 : CSV Files (25 marks) -}
{------------------------------------------------------------------------}
{- This part involves outputing, filtering, and parsing CSV (comma
separated values) files.
A CSV file represented in memory consists of a header with some
field names, and a list of records: -}
type CSVFile = (FieldNames, [CSVRecord])
{- where a record is a list of Strings: -}
type CSVRecord = [String]
{- and so are fieldnames: -}
type FieldNames = [String]
{- Here is an example 'database' of mountains in Scotland with their
heights in metres: -}
mountains :: CSVFile
mountains =
( ["name", "height"],
[ ["Ben Nevis", "1345"]
, ["Ben Macdui", "1309"]
, ["Braeriach", "1296"]
, ["Cairn Toul", "1291"]
, ["Sgor an Lochain Uaine", "1258"]
, ["Cairn Gorm", "1245"]
, ["Aonach Beag", "1234"]
, ["Aonach Mòr", "1220"]
, ["Càrn Mòr Dearg", "1220"]
, ["Ben Lawers", "1214"]
, ["Beinn a' Bhùird", "1197m"]
, ["Beinn Mheadhoin", "very, very high"]
])
{- Of course, as with any real world database, this database contains
nonsense and needs to be cleaned. Here is a fixed version: -}
mountainsFixed :: CSVFile
mountainsFixed =
( ["name", "height"],
[ ["Ben Nevis", "1345"]
, ["Ben Macdui", "1309"]
, ["Braeriach", "1296"]
, ["Cairn Toul", "1291"]
, ["Sgor an Lochain Uaine", "1258"]
, ["Cairn Gorm", "1245"]
, ["Aonach Beag", "1234"]
, ["Aonach Mòr", "1220"]
, ["Càrn Mòr Dearg", "1220"]
, ["Ben Lawers", "1214"]
, ["Beinn a' Bhùird", "1197"]
, ["Beinn Mheadhoin", "1183"]
])
{- 3.2.0 Printing CSV Files
Write a function that converts a 'CSVFile' to a String as an actual
comma separated file.
For the purposes of this exercise, the format of a CSV file is:
- A sequence of records, where each record is on a line terminated
with either a newline ('\n', Unix-style) or a CRLF ('\r\n',
Windows-style).
- Each record consists of zero or more fields separated by commas
(',')
- Each field is either:
- a sequence of non-comma and non-newline characters; or
- zero or more spaces (which are ignored), a quoted string, and
zero or more spaces (again ignored).
The first record is taken to be the fieldnames, and the remaining
records are normal data (so there must be at least one line).
Note that there are choices when outputing strings as CSV
fields. It is always safe to output them with quotes (as long as
you quote any special characters like '"'s or newlines), but you
will get more marks if you are selective about which fields you
quote. For example, we could quote everything:
Source Code
MAIN
module Main where
import Data.List (intersperse)
import System.Environment (getArgs)
import System.Exit (exitFailure)
import Control.Monad (filterM)
import Result
import ParserCombinators
import Ex3
{- 3.3.0
Edit to this to implement a command line tool for filtering
CSV files: -}
liftResult :: Result a -> IO a
liftResult (Ok a) = return a
liftResult (Error msg) = do putStrLn ("ERROR: " ++ msg)
exitFailure
filterCSVFile :: Expr -> CSVFile -> Result CSVFile
filterCSVFile expr (hdr, xs) = do
fs <- (filterM filterBool xs)
return (hdr, fs)
where
filterBool ys = do
x <- (eval (zip hdr (map (\s -> StringValue s) ys)) expr);
case x of
BoolValue True -> return True
BoolValue False -> return False
_ -> Error "Expected boolean expression"
processFile :: String -> String -> String -> IO()
processFile exprs fname fields =
do
contents <- readFile fname
csv <- liftResult $ parseWith parseCSVFile contents
expr <- liftResult $ parseWith parseExpr exprs
(h, s) <- liftResult $ filterCSVFile expr csv
case fields of
[] -> putStr (stringOfCSVFile (h, s))
fs ->
do
flds <- liftResult $ parseWith (sepBy (isChar ',') parseCSVField) fs;
if and (map (\n -> (inArray n h)) flds) then
putStr (stringOfCSVFile (filterField flds (h, s)))
else
do putStrLn "ERROR: Invalid filter field"; exitFailure
where
filterField field (h,s) =
(filter (\n -> (inArray n field)) h,(map (\z -> map (\(_,c) -> c) (filter (\(n,_) -> (inArray n field)) z)) (map (\x-> zip h x) s)))
inArray xs ys = any (\y -> xs == y) ys
main :: IO ()
main =
do
args <- getArgs
case args of
[] -> do putStrLn ("Usage: Ex3 expr CSV \"field1,field2,...\""); exitFailure
[_] -> do putStrLn ("ERROR: missing CSV filename"); exitFailure
[exprs, fname] -> processFile exprs fname ""
[exprs,fname,fs] -> processFile exprs fname fs
_ -> do putStrLn ("ERROR: too many arguments"); exitFailure