天之间的计算差异 [英] Calculation difference between Days
问题描述
我无法解决这个问题.我有以下代码:
I can't get my head around this. I have the following Code:
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文件中读取值,其中一个值是Day.我已经设法使这些工作正常进行,直到我必须计算出该物料与该物料到期之日之间的差额.我不知道如何计算日.我收到的错误如下:
Which I use to read values from a CSV File, where one Value is a Day. I already managed to get these working until I have to compute the difference of today to the day the Item will expire. I don't know how to compute the Day. The Error I get is the following:
/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)
| ^^^^^^^^^^^^^^^^^^^^^^
欢迎任何帮助,因为我必须在今天午夜之前完成此作业……
Any help is welcome, as I have to finish this homework till Midnight today...
推荐答案
一个常见的错误是在没有Monadic上下文的函数中使用do
.这是为什么 do
表示法被认为有害的原因之一 [Haskell-wiki] . do
表达式实际上是语法糖. Haskell报告描述了如何" desugar "这些.
A common mistake is to use do
in functions that have no monadic context. It is one of the reasons why do
notation is considered harmful [Haskell-wiki]. do
expressions are in fact syntactical sugar. The Haskell report describes how to "desugar" these.
对于类似listToItem :: [String] -> Item
的功能,您不应使用do
表示法.这将不起作用,尤其是因为Item
不是
For functions like listToItem :: [String] -> Item
, you should not use do
notation. This will not work, especially since Item
is not a Monad
type.
例如,我们可以将listToItem
实现为:
We can for example implement listToItem
as:
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
参数计算差值:
In order to calculate the daysAway
, it might be better to make this a pure function, and calculate the difference with a Day
parameter:
daysAway :: Day -> Day -> Integer
daysAway = flip diffDays
analyseItems
然后可以 filter :: (a -> Bool) -> [a] -> [a]
daysAway
上的项目:
The analyseItems
then can just filter :: (a -> Bool) -> [a] -> [a]
the items on the daysAway
:
analyseItems :: Day -> [Item] -> [Item]
analyseItems today = filter ((0 >) . daysAway today . expire)
因此,在这里我们可以获得在给定的Day
到期的Item
的列表.我们根本不需要getExpired
函数,也无需使用递归进行过滤.
Here we thus can obtain a list of Item
s that are expired at a given Day
. We do not need the getExpired
function here at all, or use recursion to filter.
我们可以transform
使用 map :: (a -> b) -> [a] -> [b]
:
transform :: [[String]] -> [Item]
transform = map listToItem
现在我们可以制作一个IO Item
来获取过期的物品,例如:
Now we can make an IO Item
to obtain the expired items like:
getExpired :: [Item] -> IO [Item]
getExpired items = fmap (flip analyseItems items) today
我保留解析csv文件,通过transform
处理它,然后作为练习使用getExpired
对其进行过滤.
I leave parsing the csv file, processing it through transform
, and then filtering it with getExpired
as an exercise.
这篇关于天之间的计算差异的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!