我正在努力使用Haskell编程。
我有下面的列表,我想让它相互堆叠,所以它就像是3 x 4像素的图像。例如:
如何更改第一行或第二行的值... 例如:说我想让它更暗或更白(0代表黑色,255代表白色)
type Pixel = Int
type Row = [Pixel]
type PixelImage = [Row]
print :: PixelImage
print = [[208,152,240,29],[0,112,255,59],[76,185,0,152]]
我在这里得到的代码没有堆叠列表,我不知道如何堆叠它。
请帮助,我真的很挣扎。
提前致谢!
答案 0 :(得分:8)
为图片使用print
以外的名称,以避免与Prelude的print
发生冲突。
type Pixel = Int
type Row = [Pixel]
type PixelImage = [Row]
img :: PixelImage
img = [[208,152,240,29],[0,112,255,59],[76,185,0,152]]
这是一种效率低下的表现形式,但它可以用于学习练习。
您可以打印一个PixelImage
,其中的行堆叠在一起,并在源代码的顶部添加一些导入和I / O操作:
import Control.Monad
import Data.List
import Text.Printf
printImage :: PixelImage -> IO ()
printImage img =
forM_ img $ putStrLn . intercalate " " . map (printf "%3d")
这可能看起来令人生畏,但那里的一切都很熟悉。单词顺序有点搞笑。对于Row
中的每个PixelImage
(forM_
,很像其他语言中的for
循环),我们打印putStrLn
){{{ 1}}由两个空格分隔的值(感谢intercalate
)并用空格左边填充以制作统一的3个字符的字段(printf
)。
根据你问题中的图片,我们得到了
ghci> printImage img 208 152 240 29 0 112 255 59 76 185 0 152
Haskell列表不可变:您无法就地修改或破坏性修改。相反,可以考虑制作一个与原始列表不同的列表,除了指定的行。
Pixel
这使您的函数有机会触发modifyRow :: PixelImage -> (Row -> Row) -> Int -> PixelImage
modifyRow img f i = map go (zip [0..] img)
where go (j,r) | i == j = f r
| otherwise = r
中的每个Row
。假设您想要将特定行清零:
ghci> printImage $ modifyRow img (map $ const 0) 0 0 0 0 0 0 112 255 59 76 185 0 152
反转一行是
ghci> printImage $ modifyRow img reverse 0 29 240 152 208 0 112 255 59 76 185 0 152
在另一种语言中,您可以编写PixelImage
,但在Haskell中它是
ghci> modifyRow img (const [1..4]) 2 [[208,152,240,29],[0,112,255,59],[1,2,3,4]]
这种用法并不十分令人回味,因此我们可以用img[2] = [1,2,3,4]
来定义setRow
,这是函数式编程中的常用技术。
modifyRow
一些好的:
ghci> printImage $ setRow img [4,3,2,1] 1 208 152 240 29 4 3 2 1 76 185 0 152
也许您想要缩放像素值。
setRow :: PixelImage -> Row -> Int -> PixelImage
setRow img r i = modifyRow img (const r) i
例如:
ghci> printImage $ scaleRow img 0.5 1 208 152 240 29 0 56 127 29 76 185 0 152
添加scaleRow :: (RealFrac a) => PixelImage -> a -> Int -> PixelImage
scaleRow img x i = modifyRow img f i
where f = let clamp z | z < 0 = 0
| z > 255 = 255
| otherwise = truncate z
in map (clamp . (x *) . fromIntegral)
以将缩放因子应用于scaleImage
中的每个Pixel
意味着进行一些重构以避免在多个位置重复相同的代码。我们希望能够使用
PixelImage
得到,说
ghci> printImage $ scaleImage 3 img 255 255 255 87 0 255 255 177 228 255 0 255
这意味着scaleImage :: (RealFrac a) => a -> PixelImage -> PixelImage
scaleImage x = map $ scaleOneRow x
应为
scaleOneRow
将scaleOneRow :: (RealFrac a) => a -> Row -> Row
scaleOneRow x = map (clamp . (x *) . fromIntegral)
提升为clamp
值的顶级函数。
Pixel
这反过来简化了clamp :: (RealFrac a) => a -> Pixel
clamp z | z < 0 = 0
| z > 255 = 255
| otherwise = truncate z
:
scaleRow
答案 1 :(得分:0)
这是一个简单的列表操作。
import Prelude
get :: Int -> [a] -> a
get 0 (x : xs) = x
get i (x : xs) = get (i - 1) xs
get i [] = error "get: i is not in list"
ghci中
*Main> get 1 (get 2 ["what", "is", "up", "man?"])
'p'
设置你可以使用的东西
set :: Int -> a -> [a] -> [a]
set 0 t (x : xs) = (t : xs)
set i t (x : xs) = [x] ++ (set (i - 1) t xs)
set i _ [] = error "set: i is not in list"
使用类似
的命令set 2 (set 1 't' $ get 2 ["what", "is", "up", "man?"]) ["what", "is", "up", "man?"]
我希望有所帮助。