如何在Haskell中使用Gloss加载多张图片?如何将[IO Picture]转为[Picture]
问题核心原因
你当前的报错来自两个问题:
- 类型不匹配:
loadBMP返回的IO Picture不是已经加载完成的图片,而是**「加载图片的操作」**,只有执行这个操作才能拿到实际的Picture值。你写的loadPieceImages类型是[IO Picture],代表「包含13个独立加载操作的列表」,而main的do块中<-语法要求右侧必须是单个IO操作,因此直接绑定会报错。你需要把多个IO操作合并为一个批量操作,得到IO [Picture]类型,才能用<-取出里面的[Picture]值。 - 多余的do关键字:你原来的
loadPieceImages里的do是冗余的,do块仅用来组合多个IO/monad操作,你这里只有一个map表达式,不需要加do。
修复代码
你可以直接用mapM函数完成「批量映射+合并IO操作」的逻辑,修改后代码如下:
-- 函数类型改为IO [Picture],代表「加载所有图片、返回图片列表的操作」 loadPieceImages :: IO [Picture] loadPieceImages = mapM (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 -- 现在这里拿到的就是[Picture]类型,不会报错 play window (makeColor 1 0 0 1) 30 initialState draw transform (const id)
如果你想保留原来的map写法,也可以套一层sequence函数,效果完全等价:
loadPieceImages :: IO [Picture] loadPieceImages = sequence $ map (loadBMP . (\n -> "images/" ++ n ++ ".bmp") . (\n -> if n < 6 then show n ++ "-w" else show (n `mod` 6) ++ "-b")) [0 .. 12]
基础规则说明
不用先深入理解monad也可以记住这几个常用的IO批量操作规则:
- 如果你有
[IO a](一堆返回a的IO操作),用sequence可以转成IO [a](执行所有操作、返回结果列表的单个IO操作) - 如果你要对一个列表的每个元素执行返回IO的函数,直接用
mapM f 列表,等价于sequence (map f 列表),写法更简洁 - do块里的
<-只能用来取出单个IO操作里的值,左边变量的类型就是IO后面跟着的类型,比如IO [Picture]用<-取出的变量就是[Picture]类型
内容的提问来源于stack exchange,提问作者Maheer Ali
相关产品推荐
相关产品推荐

