我正在尝试读取CSV文件,其中第一行包含每列的名称。然后我必须适当地编辑这些文件。我有一个想法,当我第一次读入文件,然后创建一个名为Record的新数据类型,然后所有后来的记录只是这种类型的实例,现在很明显,如果程序只需处理一种类型的CSV文件一定数量的列这很容易,但遗憾的是,情况并非总是如此。
所以我的问题是你可以做点什么吗
createRecordClass (x:xs) = data Record {addRecord(x:xs)}
addRecord (x:xs) = x::String, addRecord xs
或者我只是说疯了,只是有一个列表代表一切会更容易吗?
答案 0 :(得分:1)
您可以使用Template Haskell来达到您想要的效果。这是一种通过Haskell生成Haskell代码的强大技术(类似于lisp中的宏)。
由于您提到您希望csv文件的标头创建自定义数据类型,因此您需要读入该文件,然后在Template Haskell中生成数据类型。 我看到的最接近你描述的解决方案是Yesod中的CRUD系统。查看Persistent上的Hackage个包。
答案 1 :(得分:0)
如果你在编译时有一组有限的csv文件类型,你可以用模板haskell写一些东西。例如,如果您有两种类型的csv文件:一个日志记录csv文件和一个选项csv文件,并且您有以下两个示例文件:
//sample_logger.csv
Date,Action,Succeeded
20110808,print log,true
20110929,save db,false
// sample_options.csv
Option,Value
backgroundColor,green
name,Fred
然后你可以编写一个模板haskell函数来读取这些文件的第一行,并创建一个OptionsCSVLine
和LoggerCSVLine
数据类型,具有readOptionsCVS :: FilePath -> IO [OptionsCSVLine]
和readLoggerCSV :: FilePath -> IO [LoggerCSVLine]
函数。例如:
-- CSVReader.hs
makeCSVReader :: String -> FilePath -> Q [Dec]
makeCSVReader dataTypeName sampleFilePath = sequence [makeDataType,makeReaderFunc] where
makeDataType = undefined -- todo
makeReaderFunc = undefined -- todo
-- main.hs
import CSVReader
makeCVSReader "OptionsCSV" "sample_options.csv"
makeCVSReader "LoggerCSV" "sample_logger.csv"
main = do
logLines <- readLoggerCSV "some_logger_file.csv"
print $ map loggerLineDate logLines -- print all the dates in the log file
但是,如果要处理运行时提供的任何csv文件,则无法以任何方式处理。