2011-09-02 64 views
7

想象一下,一個命令式的渲染引擎將精靈傳送到一個稍後顯示的位圖上。這在很大程度上依賴於能夠有效地突變位圖中的各個像素。我如何做這樣一個沒有副作用的語言?我想要一個完全不同的數據結構?我將如何想象Haskell中基於像素的渲染?

回答

5

您可以將任何使用可變狀態的算法轉換爲一種「串」狀態的算法。 Haskell提供了一種這樣做的方式,使得它仍然像Monad狀態下的命令式編程一樣。

雖然,在我看來,基本的blit操作可以在更實用的風格中完成。您基本上將兩個位圖組合起來,通過逐像素操作來生成新的位圖。這聽起來對我很有用。

高品質勢在必行代碼往往比良好的功能代碼快,但如果你願意放棄一些速度,你通常可以在純功能性的風格創造非常好的架構

4

Haskell有副作用,你應該在適當的時候使用它們。一個高速blit例程將會出現在你的內部循環中(因此對性能至關重要)肯定是一個適合變化的地方,所以請使用它!你有幾個選項:

  • 使用ST(U)陣列或IO(U)陣列在Haskell中自己滾動。不建議。
  • 用C語言自己編寫,然後用FFI調用它。不建議。
  • 使用已經提供這種操作的許多圖形工具包之一,並且已經花費了數百個程序員時間來製作具有高性能的良好接口,如Gtk或OpenGL。強烈推薦。

享受!

1

表示的圖像的天然功能性的方式是通過使用指數函數:

Image :: (Int,Int) -> Color 

利用該表示中,從一個圖像塊傳輸一個區域到另一個區域將與

blit area a b = \(x,y) -> if (x,y) `isInsideOf` area then a (x,y) else b (x,y) 

如果實現翻譯或其他轉換是必需的,它可以直接應用於座標:

translate (dx,dy) image = \(x,y) -> b (x+dx,y+dy) 

此表示法爲您提供了使用圖像點的自然方式。你可以,例如,易與非矩形區域工作,做花樣喜歡拍圖像插值作爲單獨的功能而不是你通常的圖像縮放算法部分:

quadraticInterpolation :: ((Int,Int) -> Color) -> ((Double,Double) -> Color) 

的性能可能在某些情況下受苦,比如當你將多個圖像分成一個,然後對結果進行計算。這導致每個連續計算的每個像素的測試鏈。但是,通過應用記憶,我們可以暫時將函數表達式轉換爲數組,並將其轉換回索引函數,從而消除了後續操作的性能。

請注意,memoization也可用於引入並行過程。