Применить функцию к списку пользовательских структур данных - PullRequest
2 голосов
/ 16 июня 2019

Исходя из моего предыдущего вопроса: Расчетная разница между днями Я не хочу применять функцию к списку моей пользовательской структуры данных Item. Проблема в том, что я до сих пор не понимаю, как правильно обрабатывать IO, поэтому вот мой код:

data Item = Item
    { name :: String
    , expire :: Day
    , stock :: Integer
    , price :: Float
    } deriving (Show)

totalLoss :: IO [Item] -> Float
totalLoss items = sum $ map loss items

loss :: Item -> Float
loss x = (price x) * fromIntegral (stock x)

Скажем так, я не могу получить только [Item], поэтому я должен правильно обработать IO. Но что бы я ни делал, я все равно получаю эти ошибки:

    • Couldn't match expected type ‘[IO Item]’
                  with actual type ‘IO [Item]’
    • In the second argument of ‘map’, namely ‘items’
      In the second argument of ‘($)’, namely ‘map loss items’
      In the expression: sum $ map loss items
   |
48 | totalLoss items = sum $ map loss items
   |                                  ^^^^^

С loss :: IO Item -> Float это та же ошибка, а с loss :: IO [Item] -> Float я получаю другую ошибку.

    • Couldn't match expected type ‘[IO [Item]]’
                  with actual type ‘IO [Item]’
    • In the second argument of ‘map’, namely ‘items’
      In the second argument of ‘($)’, namely ‘map loss items’
      In the expression: sum $ map loss items
   |
48 | totalLoss items = sum $ map loss items
   |                                  ^^^^^

Как, черт возьми, я должен решить это?

Ответы [ 2 ]

5 голосов
/ 16 июня 2019

totalLoss - чистая функция, поэтому измените ее тип соответствующим образом:

totalLoss :: [Item] -> Float
totalLoss items = sum $ map loss items

Основная проблема этого вопроса, как представляется, заключается в том, что список элементов происходит из нечистого источника (который совершенноестественная вещь).

Напишите столько своего кода, сколько чистых функций, а затем скомпонуйте эти чистые функции с нечистым вводом в (или как можно ближе) к функции main:

main :: IO ()
main = do
  items <- ioItems -- :: IO [Item]
  print $ totalLoss items

Как следует из комментария, ioItems имеет тип IO [Item], но вы можете составить totalLoss с items через do запись.

Если вы не хотите полагатьсяв нотации do вы также можете составлять свои функции без этого синтаксического сахара:

main :: IO ()
main = fmap totalLoss ioItems >>= print

Эти два варианта main эквивалентны.

2 голосов
/ 16 июня 2019

Измените тип totalLoss на [Item] -> Float, затем используйте fmap, чтобы применить функцию к значению типа IO [Item]:

totalLoss :: [Item] -> Float
totalLoss items = sum $ map loss items

loss :: Item -> Float
loss x = (price x) * fromIntegral (stock x)

-- fmap totalLoss :: Functor f => f [Item] -> f Float
-- so if you have a value of v :: IO [Item], then
-- fmap totalLoss v :: IO Float
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...