Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell - converting from List to Data.Vector

After profiling my haskell program, I've found that 66% of the time in the program is spent indexing into lists. The solution seems to be using Data.Vector, but I'm having trouble converting: when I change the code to use a Vector it uses tons and tons of memory, and hangs so badly I can't even profile it. What could cause this?

Here is the file I would like to convert: https://github.com/drew-gross/Blokus-AI/blob/master/Grid.hs

and my attempt at converting it: https://github.com/drew-gross/Blokus-AI/blob/convert-to-vector/Grid.hs

Any ideas what I am doing wrong? Or at least, where to look?

like image 738
Drew Avatar asked Nov 16 '12 01:11

Drew


2 Answers

makeEmptyGrid width height defaultCell = Grid (Data.Vector.take arraySize $ fromList $ repeat defaultCell) width height

That's a killer right there. fromList converts an entire list to a Vector, but repeat defaultCell is an infinite list.

makeEmptyGrid width height defaultCell = Grid (fromListN arraySize $ repeat defaultCell) width height

or

makeEmptyGrid width height defaultCell = Grid (fromList $ replicate arraySize defaultCell) width height

would fix that.

A cursory look over the rest didn't result in further obvious traps, but I may easily have overlooked some.

like image 134
Daniel Fischer Avatar answered Oct 16 '22 19:10

Daniel Fischer


This is just an additional thought following upon Daniel. It looked like your Grids were only of Colors It probably won't do much for a small 'Grid' but it is comparatively easy to make an Unbox instance for Color. Then a grid will contain an unboxed array. In Grid.hs you would import Data.Vector.Unboxed rather than Data.Vector. This is in general much better for many reasons, but will require you to put an Unbox a => constraint on many of the definitions. This might have consequences if you want to make or 'map' into Grids full of things of another type than Color, unless it has an Unbox instance.

Below I just add the TH incantation from vector-th-unbox (I just learned about that package recently, and am taking the occasion to test it again) and the two requisite definitions. It wouldn't be much harder to write it by hand following the Bool instance in Data.Vector.Unboxed.Base.

{-#LANGUAGE TemplateHaskell, TypeFamilies, MultiParamTypeClasses#-}
module Color where

import Display
import Data.Vector.Unboxed.Deriving 
import qualified Data.Vector.Unboxed as V 
import qualified Data.Vector.Generic         as G
import qualified Data.Vector.Generic.Mutable as M 
import Data.Word (Word8)

data Color = Yellow | Red | Green | Blue | Empty      
           deriving (Show, Eq, Ord, Enum, Bounded)

fromColor :: Color -> Word8
{-# INLINE fromColor #-}
fromColor = fromIntegral . fromEnum

toColor :: Word8 -> Color
{-# INLINE toColor #-}
toColor x | x < 5 = toEnum (fromIntegral x)
toColor _ = Empty

derivingUnbox "Color"
   [t| Color -> Word8 |]
    [| fromColor |]
    [| toColor |]

-- test
colorCycle :: Int -> V.Vector Color
colorCycle n = V.unfoldr colorop 0 where 
  colorop m  | m < n =  Just (toColor (fromIntegral (m `mod` 5)),m+1)
  colorop _ =  Nothing
-- *Colour> colorCycle 12
-- fromList [Yellow,Red,Green,Blue,Empty,Yellow,
-- Red,Green,Blue,Empty,Yellow,Red]

colorBlack  = "\ESC[0;30m"
colorRed    = "\ESC[0;31m"
colorGreen  = "\ESC[0;32m"
colorYellow = "\ESC[0;33m"
colorBlue =   "\ESC[0;34m"

instance Display Color where
    display Red    = colorRed ++ "R" ++ colorBlack
    display Green  = colorGreen ++ "G" ++ colorBlack
    display Yellow = colorYellow ++ "Y" ++ colorBlack
    display Blue   = colorBlue ++ "B" ++ colorBlack
    display Empty  = "."

Edit: In versions of vector-th-unbox preceding 0.1 the following template was used:

derivingUnbox "Color"
    [d| instance Unbox' (Color) Word8 |]
    [| fromColor |]
    [| toColor |]
like image 33
applicative Avatar answered Oct 16 '22 17:10

applicative