将功能应用于自定义数据结构列表

时间:2019-06-16 14:40:06

标签: list haskell

源自我之前的问题:Calculation difference between Days 我不会将函数应用于自定义数据结构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 个答案:

答案 0 :(得分:5)

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表示法将itemsdo组成。

如果您不想依靠do表示法,也可以在没有语法糖的情况下编写函数:

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

main的这两个变体是等效的。

答案 1 :(得分:2)

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