我是Haskell的新手,正在处理代表type Img = [String]
的图像。
我想创建一个向上或向下移动图像1行或更多行的函数。
下面的图片示例。
img 1= [ "XX XX"
, " X "
, "XX XX"
]
我的目标是编写一个函数moveImg :: Int -> Img -> Img
,将图像垂直翻译,包裹; e.g:
moveImg 1 (img 1) = -- Move up by 1
[ " X "
, "XX XX"
, "XX XX"
]
moveImg (-1) (img 1) = -- Move down by 1
[ "XX XX"
, "XX XX"
, " X "
]
答案 0 :(得分:2)
你朋友的代码不起作用,因为它缺少模运算符 - 所以旋转不是“包裹”。 Carsten的代码是有效的(他的代码通过将列表与自身堆叠起来然后采用适当的切片来工作;它将“包裹”,因为它是堆叠的);这是另一种选择。这只是the array rotation problem。
import Data.List (splitAt)
import Data.Tuple (swap)
rotate :: Int -> [a] -> [a]
rotate k xs = uncurry (++) $ swap $ splitAt (k `mod` length xs) xs
我们将列表拆分为两半 - 我们mod
为了启用旋转,swap
为后面的前端,并将它们添加到一起。 swap
适用于元组(splitAt
返回)。 uncurry
只强制列表连接(++
)来处理元组而不是两个单独的参数。它将类型a -> b -> c
的函数转换为(a, b) -> c
类型。
以下是一些测试 - forM_
就像for循环一样用于按顺序打印每一行。
import Control.Monad (forM_)
main = do
let img = ["XX XX",
" X ",
"XX XX"]
putStrLn "Up is positive"
forM_ (rotate 1 img) print
putStrLn "Down is negative"
forM_ (rotate (-1) img) print
提供以下输出:
Up is positive
" X "
"XX XX"
"XX XX"
Down is negative
"XX XX"
"XX XX"
" X "
如果您愿意,可以创建Up
/ Down
数据类型,而不是使用正/负值。 e.g。
data Direction = Up | Down
rotate :: Direction -> Int -> [String] -> [String]
rotate d k xs = . . .
答案 1 :(得分:1)
moveImg n xs = take len $ drop (mod n len) $ cycle xs
where len = length xs