Разница в расчетах между днями - PullRequest
1 голос
/ 16 июня 2019

Я не могу разобраться с этим. У меня есть следующий код:

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)
   |             ^^^^^^^^^^^^^^^^^^^^^^

Любая помощь приветствуется, поскольку я должен закончить эту домашнюю работу до полуночи сегодня ...

1 Ответ

1 голос
/ 16 июня 2019

Распространенной ошибкой является использование do в функциях, которые не имеют монадического контекста.Это одна из причин, почему запись do считается вредной [Haskell-wiki] .do выражения на самом деле синтаксический сахар отчете Haskell описывается, как " desugar " сделать это.

Для таких функций, как listToItem :: [String] -> Item, вы не должны использовать нотацию do.Это не будет работать, тем более что Item не является типом Monad.

Мы можем, например, реализовать listToItem как:

listToItem :: [String] -> Item
listToItem [] = error "Empty List"
listToItem [n, e, s, p] = <b>Item (read n) (parseDate e) (read s) (read p)</b>
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 (<b>(0 >) . daysAway today . expire</b>)

Здесь мы, таким образом, можем получить список Item s, срок действия которых истек вданное Day.Нам здесь вообще не нужна функция getExpired, или мы используем рекурсию для фильтрации.

Мы можем transform список строк до Item с map :: (a -> b) -> [a] -> [b]:

transform :: [[String]] -> [Item]
transform = <b>map</b> listToItem

Теперь мы можем сделать IO Item для получения просроченных элементов, таких как:

getExpired :: [Item] -> IO [Item]
getExpired items = fmap (flip analyseItems items) today

Я оставляю парсинг файла CSV, обрабатывая его черезtransform, а затем отфильтруйте его с помощью getExpired в качестве упражнения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...