Haskell列表帮助!

时间:2010-08-14 23:43:06

标签: haskell

我正在努力使用Haskell编程。

我有下面的列表,我想让它相互堆叠,所以它就像是3 x 4像素的图像。例如:

pixel image

如何更改第一行或第二行的值... 例如:说我想让它更暗或更白(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]]

我在这里得到的代码没有堆叠列表,我不知道如何堆叠它。

请帮助,我真的很挣扎。

提前致谢!

2 个答案:

答案 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中的每个PixelImageforM_,很像其他语言中的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?"]

我希望有所帮助。