我正在努力使用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]]
Run Code Online (Sandbox Code Playgroud)
我在这里得到的代码没有堆叠列表,我不知道如何堆叠它.
请帮忙,我真的很挣扎.
提前致谢!
使用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]]
Run Code Online (Sandbox Code Playgroud)
这是一种低效的表示,但它可以用于学习练习.
您可以打印一个PixelImage堆叠在一起的行,并在源代码顶部添加一些导入和I/O操作:
import Control.Monad
import Data.List
import Text.Printf
printImage :: PixelImage -> IO ()
printImage img =
forM_ img $ putStrLn . intercalate " " . map (printf "%3d")
Run Code Online (Sandbox Code Playgroud)
这可能看起来令人生畏,但那里的一切都很熟悉.单词顺序有点搞笑.对于每一个Row在PixelImage(forM_,很像for在其他语言中环)我们打印(使用putStrLn)的列表中Pixel有两个空格分隔值(感谢intercalate)和左填充空格令匀3个字符的字段(printf).
有了你问题的图片,我们得到了
ghci> printImage img 208 152 240 29 0 112 255 59 76 185 0 152
Haskell列表是不可变的:您不能就地修改或破坏性修改.相反,可以考虑制作一个与原始列表相同的列表,但指定的行除外.
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
Run Code Online (Sandbox Code Playgroud)
这使你的函数有机会火每个Row中PixelImage.假设您要将特定行清零:
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
在另一种语言中,你可能会写img[2] = [1,2,3,4],但在Haskell中它是
ghci> modifyRow img (const [1..4]) 2 [[208,152,240,29],[0,112,255,59],[1,2,3,4]]
这种用法并不十分令人回味,因此我们可以setRow根据modifyRow函数式编程中的常用技术进行定义.
setRow :: PixelImage -> Row -> Int -> PixelImage
setRow img r i = modifyRow img (const r) i
Run Code Online (Sandbox Code Playgroud)
更好:
ghci> printImage $ setRow img [4,3,2,1] 1 208 152 240 29 4 3 2 1 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)
Run Code Online (Sandbox Code Playgroud)
例如:
ghci> printImage $ scaleRow img 0.5 1 208 152 240 29 0 56 127 29 76 185 0 152
添加scaleImage至缩放因子应用到每个Pixel在一个PixelImage比特重构的,以避免重复在多个地方相同的代码的装置.我们希望能够使用
scaleImage :: (RealFrac a) => a -> PixelImage -> PixelImage
scaleImage x = map $ scaleOneRow x
Run Code Online (Sandbox Code Playgroud)
得到,说
ghci> printImage $ scaleImage 3 img 255 255 255 87 0 255 255 177 228 255 0 255
这意味着scaleOneRow应该
scaleOneRow :: (RealFrac a) => a -> Row -> Row
scaleOneRow x = map (clamp . (x *) . fromIntegral)
Run Code Online (Sandbox Code Playgroud)
这促进clamp了Pixel价值的顶级功能.
clamp :: (RealFrac a) => a -> Pixel
clamp z | z < 0 = 0
| z > 255 = 255
| otherwise = truncate z
Run Code Online (Sandbox Code Playgroud)
这反过来简化了scaleRow:
scaleRow :: (RealFrac a) => PixelImage -> a -> Int -> PixelImage
scaleRow img x i = modifyRow img (scaleOneRow x) i
Run Code Online (Sandbox Code Playgroud)