我在用Haskell看CSV。我不确定这样做是否合适。
这就是我要做的:
任何关于如何编写更好的Haskell代码的反馈都是非常感谢的!
代码是一个堆栈项目,您可以找到关于如何运行它的项目和说明:这里
在编写代码:我希望我在学习Haskell的时候知道之前,我阅读了Stephen指南的这一部分
下面是读取CSV文件的代码。主要功能是printStocks
。
{-# LANGUAGE OverloadedStrings #-}
module Lib (printStocks) where
import Control.Monad
import qualified Data.ByteString.Lazy as BL
import Data.Csv
import qualified Data.Vector as V
-- data type to model a stock
data Stock = Stock
{ code :: String,
name :: String,
country :: String,
exchange :: String,
currency :: String,
instrumentType :: String
}
deriving (Show)
instance FromNamedRecord Stock where
parseNamedRecord record =
Stock
<$> record .: "Code"
<*> record .: "Name"
<*> record .: "Country"
<*> record .: "Exchange"
<*> record .: "Currency"
<*> record .: "Type"
-- type synonyms to handle the CSV contents
type ErrorMsg = String
type CsvData = (Header, V.Vector Stock)
-- Function to read the CSV
parseCSV :: FilePath -> IO (Either ErrorMsg CsvData)
parseCSV filePath = do
contents <- BL.readFile filePath
return $ decodeByName contents
-- Discard headers from CsvData
removeHeaders :: CsvData -> V.Vector Stock
removeHeaders = snd
-- Check if the given element is a Common Stock
isStock :: Stock -> Bool
isStock stock = instrumentType stock == "Common Stock"
filterStocks :: V.Vector Stock -> V.Vector Stock
filterStocks = V.filter isStock
-- Print the stocks from the CSV file
printStocks :: FilePath -> IO ()
printStocks filePath =
parseCSV filePath
>>= print . fmap (filterStocks . removeHeaders)
发布于 2021-09-20 13:20:00
总体上看起来很棒,尤其是如何包含运行它的说明,即使是使用示例数据,这也使得这是一个很好的提交。
我注意到的第一件事是打开文件的错误处理。例如,parseCsv
检查文件的存在--这是一个很大的提示,表明该函数并不像预期的那样在所有情况下都能正常工作,比如如果文件存在,但是无法读取(尝试chmod a-r test-resources/empty-file.csv
并查看它如何产生一个未显示的异常*** Exception: test-resources/empty-file.csv: openBinaryFile: permission denied (Permission denied)
)。根据签名,我实际上希望通过Either
来处理这个问题:
parseCsv filePath = do
result <- try $ BL.readFile filePath
return $ case result of
Left (exception :: IOException) -> Left $ show exception
Right contents -> decodeByName contents
我相信这会做得更好,这一次也需要启用ScopedTypeVariables
。
IMO Csv
看起来很奇怪,但是这个包已经使用了这个名字,我想这很好。
有些评论可能会更好,比如parseCsv
说“函数读取CSV”--嗯,是的,我们已经从名字中看到了这一点。可能“从文件中读取原始CSV数据”,类似于readStocks
。
我可能会在filterStocks
中内联本地函数,因为我认为它没有为匿名函数增加太多的清晰度:
filterStocks = V.filter (\instrument -> instrumentType instrument == "Common Stock")
由于您已经自由地使用了fmap
,所以我还考虑了以下几点:
filterStocks = V.filter $ fmap (== "Common Stock") instrumentType
然而,我认为它实际上使它在可读性方面更糟。
类似地,readStocks
及其fmap . fmap
太复杂了,我跟不上。我认为,对下一位读者来说,稍微扩展一下它可能会更好。
https://codereview.stackexchange.com/questions/268038
复制相似问题