从列表中选择特定图片
Pick a specific picture from a list
我有以下功能:
blockToPicture :: Int -> [Picture] -> Picture
blockToPicture n [pic1,pic2,pic3] | n==0 = ...
| n==1 = ...
| otherwise = ...
如果n==0
我想selectpic1
,如果n==1
我想selectpic2
。不然我要selectpic3
。问题是其中一张图片没有加载,所以它没有出现在列表中。
而不是 [pic1,pic2,pic3]
我有类似 [Pic1,Pic3]
的东西。
当函数是 supposed
到 select 一张不在列表中的图片时,我希望它写成 "X"
。为此,我将使用该功能
text "X"
代替。问题是我不知道如何让它写 "X"
而不是 select 错误的图片。
编辑:
我创建了以下函数,但由于某种原因,我收到图片错误 "Variable not in scope"。
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"
I'm getting the error "Variable not in scope" to the pictures.
表达式 elem x xs
检查给定的 x
是否在列表 xs
中。在您编写 pic1
的代码中,范围内没有这样的变量,它没有在任何地方定义。在任何情况下,您都不想在列表中搜索特定值,而是想知道给定位置是否“存在”,即列表是否足够长。
此外,您不能只在具有这种类型的函数中“编写”。在Haskell中,输入和输出反映在类型上。这是一个纯函数,接受一些参数并计算结果,没有副作用。
所以你在这里可以做的是return一个Maybe Picture
,它的值是Nothing
或Just pic
,这取决于你是否可以return一张图片或不是。或者您可以使用 Either String Picture
,其中值的形式为 Left string
或 Right pic
。让我们选择后一个选项。
blocoParaPicture :: Int -> [Picture] -> Either String Picture
在实施方面,我们可以偏离主题,讨论错误管理(因为问题是访问某个位置可能会失败)。但在这一点上,我认为最好避免走弯路,所以让我们保持(相对)简单。
直接递归(最简单)
最简单最直接的方法是直接递归(正如@chepner 在下面评论中所建议的那样)。
blocoParaPicture :: Int -> [Picture] -> Either String Picture
blocoParaPicture _ [] = Left "X"
blocoParaPicture 0 (x:_) = Right x
blocoParaPicture n (x:xs) = safe (n-1) xs
确保!!
成功
如果您确实想使用标准访问函数 !!
,一种解决方法(但在一般情况下可能效率低下)是构造一个“安全”无限列表。
import Data.List
blocoParaPicture :: Int -> [Picture] -> Either String Picture
blocoParaPicture n xs = zs !! n
where zs = [Right x | x <- xs] ++ repeat (Left "X")
列表zs
是由两个列表组成的无限列表。第一个 [Right x | x <- xs]
就像你原来的列表,但每个元素 x
变成 Right x
。然后从那时起,所有元素的形式都是 Left "X"
以指示失败。一般来说,上述方法可能效率低下。如果您在列表中查找大 n
:
[Right 1, Right 2] ++ [Left "X", Left "X", ...
您正在执行许多不必要的步骤,因为您可以在第一个列表结束时停止。但是对于小 n
.
来说工作得很好
使用lookup
还有另一种可能性,类似于您尝试使用 elem
函数,是在索引上使用 lookup
。此功能在设计上是安全的。
lookup :: Eq a => a -> [(a, b)] -> Maybe b
按照这种方法,您首先构建列表,
[(0,x0), (1,x1), (2,x2) ...(k,xk)]
然后查找给定的 n
到 return 关联的 xn
(或 Nothing
)。
blocoParaPicture' :: Int -> [Picture] -> Maybe Picture
blocoParaPicture' n xs = lookup n (zip [1..] xs)
This returns Nothing
虽然没有找到。但如果您愿意,可以通过 maybe :: b -> (a -> b) -> Maybe a -> b
.
转换为 Either
blocoParaPicture :: Int -> [Picture] -> Either String Picture
blocoParaPicture n xs = maybe (Left "X") Right (lookup n (zip [1..] xs))
当您只需要一个简单的访问函数时,这肯定有点太复杂了。但在事情不那么简单的情况下可以派上用场。
您不能只丢弃未加载的图片;如果您尝试加载 3 张图片并以 [some_pic, some_other_pic]
结束,您怎么知道哪一张没有加载?您需要一个 [Maybe Picture]
类型的列表,其中 Just pic
表示加载成功的图片,而 Nothing
表示加载失败。那么你的函数看起来像
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
采纳 Jorge Adriano 的建议以使用 lookup
(这是一个很好的建议)
import Control.Monad
blockToPicture :: Int -> [Maybe Picture] -> Maybe Picture
blockToPicture n pics = join (lookup n (zip [0..] pics))
由于 lookup :: a -> [(a,b)] -> Maybe b
和 b
这里是 Maybe Picture
,我们有
lookup
returns Nothing
如果 n
太大的场景; Just Nothing
如果所需图片加载失败,Just (Just pic)
如果找到所需图片。 Control.Monad
中的 join
函数将 lookup
returns 的 Maybe (Maybe Picture)
值减少为我们想要的 "regular" Maybe Picture
。
我有以下功能:
blockToPicture :: Int -> [Picture] -> Picture
blockToPicture n [pic1,pic2,pic3] | n==0 = ...
| n==1 = ...
| otherwise = ...
如果n==0
我想selectpic1
,如果n==1
我想selectpic2
。不然我要selectpic3
。问题是其中一张图片没有加载,所以它没有出现在列表中。
而不是 [pic1,pic2,pic3]
我有类似 [Pic1,Pic3]
的东西。
当函数是 supposed
到 select 一张不在列表中的图片时,我希望它写成 "X"
。为此,我将使用该功能
text "X"
代替。问题是我不知道如何让它写 "X"
而不是 select 错误的图片。
编辑: 我创建了以下函数,但由于某种原因,我收到图片错误 "Variable not in scope"。
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"
I'm getting the error "Variable not in scope" to the pictures.
表达式 elem x xs
检查给定的 x
是否在列表 xs
中。在您编写 pic1
的代码中,范围内没有这样的变量,它没有在任何地方定义。在任何情况下,您都不想在列表中搜索特定值,而是想知道给定位置是否“存在”,即列表是否足够长。
此外,您不能只在具有这种类型的函数中“编写”。在Haskell中,输入和输出反映在类型上。这是一个纯函数,接受一些参数并计算结果,没有副作用。
所以你在这里可以做的是return一个Maybe Picture
,它的值是Nothing
或Just pic
,这取决于你是否可以return一张图片或不是。或者您可以使用 Either String Picture
,其中值的形式为 Left string
或 Right pic
。让我们选择后一个选项。
blocoParaPicture :: Int -> [Picture] -> Either String Picture
在实施方面,我们可以偏离主题,讨论错误管理(因为问题是访问某个位置可能会失败)。但在这一点上,我认为最好避免走弯路,所以让我们保持(相对)简单。
直接递归(最简单)
最简单最直接的方法是直接递归(正如@chepner 在下面评论中所建议的那样)。
blocoParaPicture :: Int -> [Picture] -> Either String Picture
blocoParaPicture _ [] = Left "X"
blocoParaPicture 0 (x:_) = Right x
blocoParaPicture n (x:xs) = safe (n-1) xs
确保!!
成功
如果您确实想使用标准访问函数 !!
,一种解决方法(但在一般情况下可能效率低下)是构造一个“安全”无限列表。
import Data.List
blocoParaPicture :: Int -> [Picture] -> Either String Picture
blocoParaPicture n xs = zs !! n
where zs = [Right x | x <- xs] ++ repeat (Left "X")
列表zs
是由两个列表组成的无限列表。第一个 [Right x | x <- xs]
就像你原来的列表,但每个元素 x
变成 Right x
。然后从那时起,所有元素的形式都是 Left "X"
以指示失败。一般来说,上述方法可能效率低下。如果您在列表中查找大 n
:
[Right 1, Right 2] ++ [Left "X", Left "X", ...
您正在执行许多不必要的步骤,因为您可以在第一个列表结束时停止。但是对于小 n
.
使用lookup
还有另一种可能性,类似于您尝试使用 elem
函数,是在索引上使用 lookup
。此功能在设计上是安全的。
lookup :: Eq a => a -> [(a, b)] -> Maybe b
按照这种方法,您首先构建列表,
[(0,x0), (1,x1), (2,x2) ...(k,xk)]
然后查找给定的 n
到 return 关联的 xn
(或 Nothing
)。
blocoParaPicture' :: Int -> [Picture] -> Maybe Picture
blocoParaPicture' n xs = lookup n (zip [1..] xs)
This returns Nothing
虽然没有找到。但如果您愿意,可以通过 maybe :: b -> (a -> b) -> Maybe a -> b
.
Either
blocoParaPicture :: Int -> [Picture] -> Either String Picture
blocoParaPicture n xs = maybe (Left "X") Right (lookup n (zip [1..] xs))
当您只需要一个简单的访问函数时,这肯定有点太复杂了。但在事情不那么简单的情况下可以派上用场。
您不能只丢弃未加载的图片;如果您尝试加载 3 张图片并以 [some_pic, some_other_pic]
结束,您怎么知道哪一张没有加载?您需要一个 [Maybe Picture]
类型的列表,其中 Just pic
表示加载成功的图片,而 Nothing
表示加载失败。那么你的函数看起来像
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
采纳 Jorge Adriano 的建议以使用 lookup
(这是一个很好的建议)
import Control.Monad
blockToPicture :: Int -> [Maybe Picture] -> Maybe Picture
blockToPicture n pics = join (lookup n (zip [0..] pics))
由于 lookup :: a -> [(a,b)] -> Maybe b
和 b
这里是 Maybe Picture
,我们有
lookup
returns Nothing
如果 n
太大的场景; Just Nothing
如果所需图片加载失败,Just (Just pic)
如果找到所需图片。 Control.Monad
中的 join
函数将 lookup
returns 的 Maybe (Maybe Picture)
值减少为我们想要的 "regular" Maybe Picture
。