Skip to content

Instantly share code, notes, and snippets.

@tanakh
Created November 27, 2012 05:55
Show Gist options
  • Select an option

  • Save tanakh/4152608 to your computer and use it in GitHub Desktop.

Select an option

Save tanakh/4152608 to your computer and use it in GitHub Desktop.
ADTをUnboxed Vectorにして、Lens経由でアクセスする ref: http://qiita.com/items/3a2053bea740ca423407
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
import Control.Lens hiding (Rep, from, to)
import Data.Array.Repa as Repa
import Data.Array.Repa.Eval
import Data.Vector.Generic.Lens
import qualified Data.Vector.Unboxed as VU
import Data.Vector.Unboxed.Deriving
import GHC.Generics as G
data FluidCell a
= FluidCell
{ _mass :: !a
, _energy :: !a
, _volume :: !a
}
deriving (Eq, Show, Generic)
makeLenses ''FluidCell
derivingUnbox "FluidCell"
[t| VU.Unbox a => FluidCell a -> (a, a, a) |]
[e| \(FluidCell x y z) -> (x, y, z) |]
[e| \(x, y, z) -> FluidCell x y z |]
--- generic definition
class GElt f where
gtouch :: f a -> IO ()
gzero :: f a
gone :: f a
instance GElt U1 where
gtouch _ = return ()
gzero = U1
gone = U1
instance (GElt a, GElt b) => GElt (a :*: b) where
gtouch (x :*: y) = gtouch x >> gtouch y
gzero = gzero :*: gzero
gone = gone :*: gone
instance (GElt a, GElt b) => GElt (a :+: b) where
gtouch (L1 x) = gtouch x
gtouch (R1 x) = gtouch x
gzero = L1 gzero
gone = L1 gone
instance (GElt a) => GElt (M1 i c a) where
gtouch (M1 x) = gtouch x
gzero = M1 gzero
gone = M1 gone
instance (Elt a) => GElt (K1 i a) where
gtouch (K1 x) = touch x
gzero = K1 zero
gone = K1 one
genericTouch :: (Generic a, GElt (Rep a)) => a -> IO ()
genericTouch = gtouch . G.from
genericZero :: (Generic a, GElt (Rep a)) => a
genericZero = G.to gzero
genericOne :: (Generic a, GElt (Rep a)) => a
genericOne = G.to gone
-----
instance Elt a => Elt (FluidCell a) where
touch = genericTouch
zero = genericZero
one = genericOne
main :: IO ()
main = do
let v = VU.fromList [FluidCell (1 :: Int) 2 3, FluidCell 4 5 6] :: VU.Vector (FluidCell Int)
print v
-- > fromList [FluidCell {_mass = 1, _energy = 2, _volume = 3},FluidCell {_mass = 4, _energy = 5, _volume = 6}]
print $ v ^._head . mass
-- > 1
print $ _head . mass .~ 9 $ v
-- > fromList [FluidCell {_mass = 9, _energy = 2, _volume = 3},FluidCell {_mass = 4, _energy = 5, _volume = 6}]
print $ ordinal 1 . energy .~ 9 $ v
-- > fromList [FluidCell {_mass = 1, _energy = 2, _volume = 3},FluidCell {_mass = 4, _energy = 9, _volume = 6}]
let a = fromListUnboxed (Z :. (2 :: Int) :. (3 :: Int)) [ FluidCell (i*2) (i*3) (i*4) | i <- [1 .. 6::Int] ]
print a
-- > AUnboxed ((Z :. 2) :. 3) (fromList [FluidCell {_mass = 2, _energy = 3, _volume = 4},FluidCell {_mass = 4, _energy = 6, _volume = 8},FluidCell {_mass = 6, _energy = 9, _volume = 12},FluidCell {_mass = 8, _energy = 12, _volume = 16},FluidCell {_mass = 10, _energy = 15, _volume = 20},FluidCell {_mass = 12, _energy = 18, _volume = 24}])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment