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

Bis*_*943 2 haskell list

源自我之前的问题:天之间的计算差异 我不想将函数应用于自定义数据结构的列表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)
Run Code Online (Sandbox Code Playgroud)

只是说,我不能得到公正,[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
   |                                  ^^^^^
Run Code Online (Sandbox Code Playgroud)

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
   |                                  ^^^^^
Run Code Online (Sandbox Code Playgroud)

我应该如何解决这个问题?

Mar*_*ann 5

totalLoss 是一个纯函数,因此请相应地更改其类型:

totalLoss :: [Item] -> Float
totalLoss items = sum $ map loss items
Run Code Online (Sandbox Code Playgroud)

这个问题的根本问题似乎是项目清单源自不纯的来源(这是完全自然的事情)。

编写尽可能多的代码作为纯函数,然后使用(或尽可能接近)该main函数的不纯输入来构成这些纯函数:

main :: IO ()
main = do
  items <- ioItems -- :: IO [Item]
  print $ totalLoss items
Run Code Online (Sandbox Code Playgroud)

作为暗示的评论,ioItems有型IO [Item],但你可以撰写totalLossitems通过do符号。

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

main :: IO ()
main = fmap totalLoss ioItems >>= print
Run Code Online (Sandbox Code Playgroud)

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