1

我对 Haskell 很陌生,目前对 monad 还没有很好的理解。我正在使用光泽来制作国际象棋。我面临的问题是加载多个图像。我正在使用loadBMPhaskell 提供的功能来加载图像。它的签名是:

loadBMP :: FilePath -> IO Picture

我可以加载单个图像,但无法加载图像数组。

-- This function calculates the path of all the images and then apply loadBMP function on it.

loadPieceImages :: [IO Picture]
loadPieceImages = do
  map (loadBMP . (\n -> "images/" ++ n ++ ".bmp") . (\n -> if n < 6 then show n ++ "-w" else show (n `mod` 6) ++ "-b")) [0 .. 12]

main :: IO ()
main = do
  images <- loadPieceImages  -- On this line I am getting error.
  play window (makeColor 1 0 0 1) 30 initialState draw transform (const id)

主要问题是我有[IO Picture]类型,但我不知道如何将它变成[Picture].

这东西可能是非常基本的,但我现在无法理解单子。所以请解释你给出的答案。

4

1 回答 1

1

由于您(正确地)声明mainIO ()do符号和<-箭头使您能够“剥离”IO包装。因此,当您编写 时images <- loadPieceImages,编译器期望loadPieceImages有一个IO类型。loadPieceImages但是,具有类型[IO Picture],这就是编译器抱怨的原因。最外层的包装是[],不是IO

另一方面,如果您有一个IO [Picture]值,则可以使用<-箭头剥离IO包装以“获取”其中的[Picture]列表。

换句话说,您需要一个类型为 的函数[IO Picture] -> IO [Picture]。您可以搜索该类型并考虑建议。

一旦你掌握了它的窍门,你就会开始注意到,每当你想“翻转”两个包装器(如IO[])的“堆叠”时,都有一个通用函数:sequence。此函数获取任何列表Monad m并将其翻转为m [a]. 由于IO是一个Monad实例,这也将在这里工作。

所以,像

images <- sequence loadPieceImages

应该可以工作(我实际上并没有尝试编译这个,因为 OP 不是一个最小的可重现示例,所以你可能需要稍微调整一下,但这是一般的想法:使用sequence)。

于 2021-12-06T08:21:45.823 回答