Функциональный эквивалент итерации по двумерному массиву - PullRequest
5 голосов
/ 11 февраля 2011

У меня есть эта функция в Haskell (я использую библиотеку Haskell-SDL):

pixel :: Surface -> Int16 -> Int16 -> Pixel -> IO Bool

pixel screen x y color

Я хочу использовать это, чтобы взять 2D-массив (или какую-либо другую структуру данных) и нарисовать его на экране, по одному пикселю за раз. Я попытался сделать это с forM_, но не могу понять, как заставить его работать с аргументами x и y.

Я довольно новичок в Хаскеле и функциональном программировании в целом. Я прорабатываю еще один учебник по Хаскеллу, но эта проблема просто поставила меня в тупик.

В случае, если это имеет отношение к решению, я пытаюсь написать raytracer. Он должен выполнить расчет для каждого пикселя, а затем записать этот пиксель на экран.

Ответы [ 3 ]

3 голосов
/ 11 февраля 2011

Если вы используете вложенные списки, выполните:

import Control.Monad
plot :: Surface -> [[Pixel]] -> IO ()
plot surf = zipWithM_ (\ y -> zipWithM_ (\ x c -> pixel surf x y c) [0..]) [0..]
2 голосов
/ 11 февраля 2011

Haskell имеет реальные массивы различных видов.Мне кажется, что вы делаете что-то совершенно неэффективное, вы хотите создать пиксельный буфер и перенести его в другой буфер?было бы намного эффективнее создать новую поверхность SDL (для которой вы можете получить / установить пиксели) и перенести ее на другую поверхность / экран или создать реальный массив пикселей и создать поверхность SDL с этим, а затем использовать процедуры блитования SDL.Если вы объясните, что вы пытаетесь сделать, я думаю, что мы можем показать вам лучший способ.

0 голосов
/ 11 февраля 2011

Вам нужно разделить две проблемы здесь.Сначала вам нужно вычислить значение пикселя.Это должно быть чистой функцией сцены и координаты луча, в который вы в нее стреляете.Затем вам нужно записать значение этого пикселя на экран.

Итак, сначала вам нужна функция:

type Coord = (Int, Int)

raytrace :: Scene -> Coord -> (Coord, Colour)  
    -- You will see why it returns this pair in a few lines

Затем вы хотите вызвать эту функцию для каждого пикселя на вашей поверхности, чтобы получитьсписок пар координат и цветов:

allCoords :: Int -> Int -> [Coord]
allCoords width height = [(x,y) | x <- [0..width], y <- [0..height]]

allPixels :: Scene -> Int -> Int -> [(Coord, Colour)]
allPixels scene w h = map (raytrace scene) (allCoords w h)

И, наконец, поместите список пикселей на поверхность дисплея с помощью функции «pixel».

writeScene :: Surface -> Scene -> Int -> Int -> IO ()
writeScene surface scene w h = mapM_ writePixel (allPixels scene w h)
    where writePixel ((x,y),c) = pixel surface x y c

Единственное, чтоФункция «pixel» возвращает «IO Bool».Я не знаю почему, поэтому я проигнорировал это, используя «mapM_», а не «mapM».

Похоже, что он создает ужасно неэффективный список пар координат-цвет и затем перебирает егонарисовать картину.Но на самом деле, благодаря ленивой природе Haskell, он фактически компилируется в цикл, который генерирует каждый цвет, а затем вызывает «пиксель» в результате.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...