csv - 天数之间的计算差异
问题描述
我无法理解这一点。我有以下代码:
module Lib
( csvFile
, analyse
) where
import Text.ParserCombinators.Parsec
import Data.Time
import Data.Time.Calendar
import qualified Data.Map as Map
data Item = Item
{ name :: String
, expire :: Day
, stock :: Integer
, price :: Float
} deriving (Show)
csvFile = endBy line eol
line = sepBy cell (char ';')
cell = quotedCell <|> many (noneOf ";\n\r")
quotedCell =
do char '"'
content <- many quotedChar
char '"' <?> "quote at end of cell"
return content
quotedChar =
noneOf "\""
<|> try (string "\"\"" >> return '"')
eol = try (string "\n\r")
<|> try (string "\r\n")
<|> string "\n"
<|> string "\r"
<?> "end of line"
parseDate :: String -> Day
parseDate dateString = parseTimeOrError True defaultTimeLocale "(%Y,%-m,%-d)" dateString :: Day
analyse :: [[String]] -> [Item]
analyse csvData = do
let items = transform h t
analyseItems items
where
h = head csvData
t = tail csvData
listToItem :: [String] -> Item
listToItem [] = error "Empty List"
listToItem [n, e, s, p] = do
let name = n
let expires = parseDate e
let stock = read s :: Integer
let price = read p :: Float
Item name expires stock price
listToItem _ = error "To few/much Arguments"
transform :: [String] -> [[String]] -> [Item]
transform line [] = do
let items = []
let item = listToItem line
item : items
transform line csvData = do
let item = listToItem line
item : (transform h t)
where
h = head csvData
t = tail csvData
analyseItems :: [Item] -> [Item]
analyseItems items = do
--let sale = getOnSale items
getExpired (head items) (tail items)
today :: IO Day
today = fmap utctDay getCurrentTime
daysAway :: Day -> IO Integer
daysAway day = fmap (diffDays day) today
getExpired :: item -> [Item] -> [Item]
getExpired item [] = do
diff <- daysAway (expire item)
case compare diff 0 of
LT -> item : []
GT -> []
EQ -> []
getExpired item items = do
diff <- daysAway (expire item)
case compare diff 0 of
LT -> item : getExpired h t
GT -> getExpired h t
EQ -> getExpired h t
where
h = head items
t = tail items
我用它从 CSV 文件中读取值,其中一个值是一天。我已经设法让这些工作,直到我必须计算今天与项目到期之日的差异。我不知道如何计算这一天。我得到的错误如下:
/home/max/Documents/haskell/Hausaufgabe_02/analysis/src/Lib.hs:85:13: error:
• Couldn't match type ‘IO’ with ‘[]’
Expected type: [Integer]
Actual type: IO Integer
• In a stmt of a 'do' block: diff <- daysAway (expire item)
In the expression:
do diff <- daysAway (expire item)
case compare diff 0 of
LT -> item : []
GT -> []
EQ -> []
In an equation for ‘getExpired’:
getExpired item []
= do diff <- daysAway (expire item)
case compare diff 0 of
LT -> item : ...
GT -> ...
EQ -> ...
|
85 | diff <- daysAway (expire item)
| ^^^^^^^^^^^^^^^^^^^^^^
/home/max/Documents/haskell/Hausaufgabe_02/analysis/src/Lib.hs:91:13: error:
• Couldn't match type ‘IO’ with ‘[]’
Expected type: [Integer]
Actual type: IO Integer
• In a stmt of a 'do' block: diff <- daysAway (expire item)
In the expression:
do diff <- daysAway (expire item)
case compare diff 0 of
LT -> item : getExpired h t
GT -> getExpired h t
EQ -> getExpired h t
In an equation for ‘getExpired’:
getExpired item items
= do diff <- daysAway (expire item)
case compare diff 0 of
LT -> item : getExpired h t
GT -> getExpired h t
EQ -> getExpired h t
where
h = head items
t = tail items
|
91 | diff <- daysAway (expire item)
| ^^^^^^^^^^^^^^^^^^^^^^
欢迎任何帮助,因为我必须在今天午夜之前完成这项作业......
解决方案
一个常见的错误是do
在没有单子上下文的函数中使用。do
这是符号被认为是有害的原因之一[Haskell-wiki]。do
表达式实际上是语法糖。Haskell 报告描述了如何“脱糖”这些。
对于类似的函数listToItem :: [String] -> Item
,你不应该使用do
符号。这是行不通的,特别是因为Item
它不是一种Monad
类型。
例如,我们可以实现listToItem
为:
listToItem :: [String] -> Item
listToItem [] = error "Empty List"
listToItem [n, e, s, p] = Item (read n) (parseDate e) (read s) (read p)
listToItem _ = error "To few/much Arguments"
为了计算daysAway
,最好将其设为纯函数,并使用Day
参数计算差异:
daysAway :: Day -> Day -> Integer
daysAway = flip diffDays
然后analyseItems
可以只是filter :: (a -> Bool) -> [a] -> [a]
上的项目daysAway
:
analyseItems :: Day -> [Item] -> [Item]
analyseItems today = filter ((0 >) . daysAway today . expire)
因此,在这里我们可以获得Item
在给定 过期的 s列表Day
。我们这里根本不需要这个getExpired
函数,或者使用递归来过滤。
我们可以使用stransform
的行列表:Item
map :: (a -> b) -> [a] -> [b]
transform :: [[String]] -> [Item]
transform = map listToItem
现在我们可以IO Item
获取过期项目,例如:
getExpired :: [Item] -> IO [Item]
getExpired items = fmap (flip analyseItems items) today
我将解析 csv 文件,通过 处理它transform
,然后将其过滤getExpired
为练习。
推荐阅读
- jetty - 如何在 Windows 上升级独立的 Jetty 安装?
- powershell - 寻找本地化以将 Get-WinEvent -Listlog 结果映射到配置 .xml 路径
- angular - 哪种方法最好 - 直接使用 URL 将 API 请求代理到另一台服务器(或)?
- javascript - 如何调用一个API,比如谷歌浏览器的webrequest api中的X(由url组成)来阻止从X获取的那组url?
- python-3.x - 使用控件时 Slycot 无法导入
- qt - 我如何知道 Qt 在哪个控制台命令上构建项目?
- google-play-console - Google Play 控制台不再在大多数设备上测试应用
- android - 如果我们将“null”数据传递给@NonNull 注释对象会发生什么?
- java - 如何将图像写入文件 – Java ImageIO
- python - 从文件中的行尾获取所有时间戳值,并对它们执行 Total 和 Average 操作