Haskell 从列表中选择特定图片
我有以下功能:Haskell 从列表中选择特定图片,haskell,gloss,juicy-pixels,Haskell,Gloss,Juicy Pixels,我有以下功能: blockToPicture :: Int -> [Picture] -> Picture blockToPicture n [pic1,pic2,pic3] | n==0 = ... | n==1 = ... | otherwise = ... 如果n==0我想选择pic1,如果n==1我想选择pic2。否则我想选择pic3。问题
blockToPicture :: Int -> [Picture] -> Picture
blockToPicture n [pic1,pic2,pic3] | n==0 = ...
| n==1 = ...
| otherwise = ...
如果n==0
我想选择pic1
,如果n==1
我想选择pic2
。否则我想选择pic3
。问题是其中一张图片没有加载,因此它不会出现在列表中。
我用类似于[pic1,pic2,pic3]
的东西代替了[pic1,pic3]
。
当函数设置为以选择列表中不存在的图片时,我希望它改为写“X”
。为此,我将使用函数
改为文本“X”
。问题是我不知道如何让它编写“X”
,而不是选择错误的图片
编辑:
我创建了以下函数,但由于某些原因,我在图片中得到了错误“变量不在范围内”
blocoParaPicture :: Int -> [Picture] -> Picture
blocoParaPicture b l | b==0 = if elem pic1 l then pic1 else text "X"
| b==1 = if elem pic2 l then pic2 else text "X"
| otherwise = if elem pic3 l then pic3 else text "X"
我将错误“变量不在范围内”添加到图片中
blocoParaPicture :: Int -> [Picture] -> Picture
blocoParaPicture b l | b==0 = if elem pic1 l then pic1 else text "X"
| b==1 = if elem pic2 l then pic2 else text "X"
| otherwise = if elem pic3 l then pic3 else text "X"
表达式elem x xs
检查给定的x
是否在列表xs
中。在编写pic1
的代码中,范围中没有这样的变量,它没有在任何地方定义。在任何情况下,您都不想在列表中搜索特定的值,而是想知道给定的位置是否“存在”,即列表是否足够长
此外,您不能仅在具有这种类型的函数中“写入”。在Haskell中,输入和输出反映在类型上。这是一个纯函数,它接受一些参数并计算结果,没有副作用
因此,您可以在这里返回一个可能是Picture
,它的值为Nothing
或Just pic
,具体取决于您是否可以返回图片。或者您可以使用字符串图片
,其中值的形式为左字符串
或右图片
。让我们选择后者
blocoParaPicture :: Int -> [Picture] -> Either String Picture
在实施方面,我们可能会偏离主题,进入错误管理的讨论(因为问题是,访问某个职位可能会失败)。但在这一点上,我认为最好避免绕道,所以让我们保持(相对)简单
直接递归(最简单)
最简单最直接的方法是直接递归(正如@chepner在下面的评论中所建议的)
确保代码>成功
如果您确实想使用标准访问功能代码>,其中一种方法(但在一般情况下可能效率低下)是构造一个“安全”的无限列表
import Data.List
blocoParaPicture :: Int -> [Picture] -> Either String Picture
blocoParaPicture n xs = zs !! n
where zs = [Right x | x <- xs] ++ repeat (Left "X")
您正在执行许多不必要的步骤,因为第一个列表结束时您可能会停止。但对于较小的n
来说效果很好
使用查找
还有一种可能性,类似于您尝试使用elem
函数,就是在索引上使用lookup
。此功能在设计上是安全的
lookup :: Eq a => a -> [(a, b)] -> Maybe b
按照这种方法,首先构建列表
[(0,x0), (1,x1), (2,x2) ...(k,xk)]
然后查找给定的n
,返回相关的xn
(或无
)
但如果未找到,则返回Nothing
。但是如果您愿意,您可以通过maybe::b->(a->b)->maybe a->b转换到或
blocoParaPicture :: Int -> [Picture] -> Either String Picture
blocoParaPicture n xs = maybe (Left "X") Right (lookup n (zip [1..] xs))
当您只需要一个简单的访问函数时,这当然有点太复杂了。但是,在事情不那么简单的情况下,这是很方便的。你不能仅仅丢弃一张没有加载的图片;如果您尝试加载3张图片,结果是[一些图片,一些其他图片]
,您如何知道哪一张没有加载?您需要一个类型为[可能图片]
的列表,其中仅pic
表示成功加载的图片,无
表示失败。那么你的函数看起来像
blockToPicture :: Int -> [Maybe Picture] -> Maybe Picture
blockToPicture _ [] = Nothing -- No pictures to choose from
blockToPicture 0 (Nothing:_) = Nothing -- Desired picture failed to load
blockToPicutre 0 (x:_) = x -- Found desired picture!
blockToPicture n (_:xs) = blockToPicture (n-1) xs -- This isn't it; try the next one
调整豪尔赫·阿德里亚诺的建议,使用查找(这是一个很好的方法)
由于lookup::a->[(a,b)]->可能是b
和b
这里是可能是图片
,我们有
如果n
太大,lookup
返回Nothing
<如果所需图片未能加载,则代码>仅为Nothing
;如果找到所需图片,则代码>仅为(仅为pic)
。来自控件的join
函数。Monad
将可能(可能图片)
值减少到lookup
返回到我们想要的“常规”可能图片
。在这里您可以再次在[pic1,pic2]
,[pic1]
和[]
等列表上进行模式匹配,每次更换不再覆盖的箱子。但是我建议您实现一个递归模式,在该模式中,您在递减的索引上递归,并在列表的尾部递归。不,不,不,您应该使用类型为[可能是图片]
的列表。文本“X”函数做什么?可以使用(字符串图片)代替。在病理情况下,n
比length xs
大得多,只检查n>length xs
比在无限列表的足够大的范围内迭代更有效。或者直接编写递归,而不是使用代码>:bPP[]=左“X”;bpp0(x:u)=右x;bppn(x:xs)=bppn(n-1)xs
。事实上,你是对的,我考虑过了。在任何情况下,他都是一个初学者,应该只看一个只有3个元素的列表。。。每种方法都会教他一些东西。你的建议补充道,也许这是最好的。试图坚持代码>可能会使它变得不必要的复杂。我还找到了的“安全”替代方案
之前,但只找到了Data.List.Safe
,但它使用了与标准函数相同的名称,这在这里会令人困惑。
blocoParaPicture' :: Int -> [Picture] -> Maybe Picture
blocoParaPicture' n xs = lookup n (zip [1..] xs)
blocoParaPicture :: Int -> [Picture] -> Either String Picture
blocoParaPicture n xs = maybe (Left "X") Right (lookup n (zip [1..] xs))
blockToPicture :: Int -> [Maybe Picture] -> Maybe Picture
blockToPicture _ [] = Nothing -- No pictures to choose from
blockToPicture 0 (Nothing:_) = Nothing -- Desired picture failed to load
blockToPicutre 0 (x:_) = x -- Found desired picture!
blockToPicture n (_:xs) = blockToPicture (n-1) xs -- This isn't it; try the next one
import Control.Monad
blockToPicture :: Int -> [Maybe Picture] -> Maybe Picture
blockToPicture n pics = join (lookup n (zip [0..] pics))