Skip to content

Commit

Permalink
Support for working with ElField.
Browse files Browse the repository at this point in the history
Fixed benchmark.
  • Loading branch information
acowley committed Jan 12, 2015
1 parent 86557fd commit 2f23ead
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 11 deletions.
41 changes: 39 additions & 2 deletions Data/Vinyl/Derived.hs
Original file line number Diff line number Diff line change
@@ -1,18 +1,55 @@
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneDeriving #-}

module Data.Vinyl.Derived where

import Data.Proxy
import Data.Vinyl.Core
import Data.Vinyl.Functor

import Foreign.Ptr (castPtr)
import Foreign.Storable
import GHC.TypeLits

data ElField (field :: (Symbol, *)) where
Field :: KnownSymbol s => t -> ElField '(s,t)
Field :: KnownSymbol s => !t -> ElField '(s,t)

type FieldRec = Rec ElField
type HList = Rec Identity
type LazyHList = Rec Thunk

deriving instance Eq t => Eq (ElField '(s,t))
deriving instance Ord t => Ord (ElField '(s,t))

instance Show t => Show (ElField '(s,t)) where
show (Field x) = (symbolVal (Proxy::Proxy s))++" :-> "++show x

-- | Get the data payload of an 'ElField'.
getField :: ElField '(s,t) -> t
getField (Field x) = x

-- | 'ElField' is isomorphic to a functor something like @Compose
-- ElField ('(,) s)@.
fieldMap :: (a -> b) -> ElField '(s,a) -> ElField '(s,b)
fieldMap f (Field x) = Field (f x)
{-# INLINE fieldMap #-}

-- | Lens for an 'ElField''s data payload.
rfield :: Functor f => (a -> f b) -> ElField '(s,a) -> f (ElField '(s,b))
rfield f (Field x) = fmap Field (f x)
{-# INLINE rfield #-}

-- | Shorthand for a 'FieldRec' with a single field.
(=::) :: KnownSymbol s => proxy '(s,a) -> a -> FieldRec '[ '(s,a) ]
(=::) _ x = Field x :& RNil

instance forall s t. (KnownSymbol s, Storable t)
=> Storable (ElField '(s,t)) where
sizeOf _ = sizeOf (undefined::t)
alignment _ = alignment (undefined::t)
peek ptr = Field `fmap` peek (castPtr ptr)
poke ptr (Field x) = poke (castPtr ptr) x
18 changes: 9 additions & 9 deletions benchmarks/StorableBench.hs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ import Control.Applicative
import Control.Lens
import Control.Monad (when)
import qualified Data.Foldable as F
import Data.Proxy
import qualified Data.Vector.Storable as V
import qualified Data.Vector.Storable.Mutable as VM
import Data.Vinyl
import Data.Vinyl.Universe.Field
import Foreign.Ptr (castPtr)
import Foreign.Storable (Storable(..))
import Linear (V2, V3, _y)
Expand All @@ -28,23 +28,23 @@ randVec n g = VM.replicateM n (uniform g) >>=
randVecStd :: (Storable a, Variate a) => Int -> IO (V.Vector a)
randVecStd = withSystemRandom . randVec

vNorm :: SField ("normal" ::: V3 a)
vNorm = SField
vNorm :: Proxy '("normal", V3 a)
vNorm = Proxy

type MyFields a = [ "pos" ::: V3 a, "tex" ::: V2 a, "normal" ::: V3 a ]
type MyVertex a = PlainRec ElField (MyFields a)
type MyFields a = [ '("pos", V3 a), '("tex", V2 a), '("normal", V3 a) ]
type MyVertex a = FieldRec (MyFields a)

doubleNviL :: V.Vector (MyVertex Float) -> V.Vector (MyVertex Float)
doubleNviL = V.map (rLens vNorm . _y *~ (2::Float))
doubleNviL = V.map (rlens vNorm . rfield . _y *~ (2::Float))

vinylNSumL :: (Num a, Storable a) => V.Vector (MyVertex a) -> a
vinylNSumL = V.sum . V.map (F.sum . view (rLens vNorm))
vinylNSumL = V.sum . V.map (F.sum . view (rlens vNorm . rfield))

doubleNvi :: V.Vector (MyVertex Float) -> V.Vector (MyVertex Float)
doubleNvi = V.map (rMod vNorm (_y *~ (2::Float)))
doubleNvi = V.map (rlens vNorm . rfield . _y *~ (2::Float))

vinylNSum :: (Num a, Storable a) => V.Vector (MyVertex a) -> a
vinylNSum = V.sum . V.map (F.sum . rGet vNorm)
vinylNSum = V.sum . V.map (F.sum . view rfield . rget vNorm)

main :: IO ()
main = do vals <- randVecStd $ n * 8 :: IO (V.Vector Float)
Expand Down

5 comments on commit 2f23ead

@acowley
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @jonsterling, can you look this over? I need a patch release pushed to hackage with at least the intent of these changes so I can push a new vinyl-gl.

A couple notes:

  • The tuple kinds are a bit awkward as you need to prime the list and tuple syntax, so you have to put a space in. For example, '[ '("Foo", Foo) ]. This isn't a deal breaker, but just to note a drawback to using the tuple kind for these purposes.
  • The length-1 Rec creation operator (=:) is used at a custom type in the tutorial, so I took (=::) for ElField. This seems a bit of tail wagging the dog to me, but I know you're not really a fan of ElField, so perhaps it is consistent with your aims. I don't feel too strongly, so it's your call.
  • I made the Field constructor strict in its argument.

@jonsterling
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. I am fine with this PR
  2. feel free to make any changes to the tutorial that you need in order to get your desired syntax
  3. Perhaps a different kind than the tuple could be used to avoid syntactic weirdness? I don't have much of an opinion on it either way since this corner of vinyl doesn't come up in my use cases, so feel free to do whatever you want :)

@jonsterling
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, just realized this is not a PR. That's fine too :)

Let me know when you are ready for me to cut a new version.

@acowley
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, it should have been a PR. It started out as just a couple instances so I did it on master and forgot I wasn't on a branch.

@jonsterling
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No problem at all!

Please sign in to comment.