2010-08-14 5 views
0

Я борюсь с программированием 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]] 

Код, который у меня здесь, не складывает список, и я не знаю, как его уложить.

Пожалуйста, помогите, я действительно борюсь с этим.

Заранее благодарен!

+3

Здесь нет действительно заметного вопроса. Вы сделали попытку, которая не работает? Вы просите общий подход? – Gian

+0

да, я прошу о помощи, потому что я не знаю, как это сделать, так как я очень новичок в haskell – James1

+2

Дайте нам пример вывода, который вы хотите получить для данного ввода. – dave4420

ответ

8

Используйте изображение, отличное от print, чтобы использовать это изображение, чтобы избежать столкновений с Prelude's 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") 

Это может выглядеть пугающим, но там все знаком. Порядок слов немного забавен. Для каждого в 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 

Это дает ваша функция шанс сгореть для каждого в 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 

Nicer:

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) 

Например:

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 

, чтобы получить, скажем

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) 

, который способствует clamp для верхнего уровня функции на Pixel значений.

clamp :: (RealFrac a) => a -> Pixel 
clamp z | z < 0  = 0 
     | z > 255 = 255 
     | otherwise = truncate z 

Это, в свою очередь, упрощает scaleRow:

scaleRow :: (RealFrac a) => PixelImage -> a -> Int -> PixelImage 
scaleRow img x i = modifyRow img (scaleOneRow x) i 
+0

Эта помощь много! Спасибо огромное! – James1

+0

извините, как если бы я хотел масштабировать все изображение, например, от первого пикселя первой строки до последнего пикселя последней строки? Я очень плохо разбираюсь в этом хэскеле. пожалуйста ... – James1

+0

@ james1 См. обновленный ответ. –

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?"] 

Я надеюсь, что помогает.

+1

'get' равен' flip (!!) ', кстати. – yatima2975

+0

@yatima - Я знаю, но парень даже, казалось, не знал простых манипуляций с списками. Лучше, на мой взгляд, показать кому-то на этом этапе код, а затем просто передать заранее построенный метод. –

Смежные вопросы