天之间的计算差异 [英] Calculation difference between Days

查看:71
本文介绍了天之间的计算差异的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我无法解决这个问题.我有以下代码:

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 Items 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆