Skip to content

Commit

Permalink
Turn ElField into a newtype (VinylRecords#150)
Browse files Browse the repository at this point in the history
  • Loading branch information
Philonous committed May 16, 2021
1 parent 4dc1dde commit 34c8305
Show file tree
Hide file tree
Showing 8 changed files with 85 additions and 32 deletions.
2 changes: 1 addition & 1 deletion Data/Vinyl.hs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ module Data.Vinyl

import Data.Vinyl.Core
import Data.Vinyl.Class.Method (RecMapMethod(..), RecPointed(..))
import Data.Vinyl.Class.Method (rmapMethodF, mapFields)
import Data.Vinyl.Class.Method (rmapMethodF)
import Data.Vinyl.Class.Method (rtraverseInMethod, rsequenceInFields)
import Data.Vinyl.ARec (ARec, toARec, fromARec)
import Data.Vinyl.Derived
Expand Down
18 changes: 9 additions & 9 deletions Data/Vinyl/Class/Method.hs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ module Data.Vinyl.Class.Method
( -- * Mapping methods over records
RecMapMethod(..)
, rmapMethodF
, mapFields
-- , mapFields
, RecMapMethod1(..)
, RecPointed(..)
, rtraverseInMethod
Expand Down Expand Up @@ -212,14 +212,14 @@ rmapMethodF :: forall c f ts. (Functor f, FieldPayload f ~ 'FieldId, RecMapMetho
rmapMethodF f = rmapMethod @c (fmap f)
{-# INLINE rmapMethodF #-}

-- | Apply a typeclass method to each field of a 'FieldRec'. This is a
-- specialization of 'rmapMethod'.
mapFields :: forall c ts. RecMapMethod c ElField ts
=> (forall a. c a => a -> a) -> FieldRec ts -> FieldRec ts
mapFields f = rmapMethod @c g
where g :: c (PayloadType ElField t) => ElField t -> ElField t
g (Field x) = Field (f x)
{-# INLINE mapFields #-}
-- -- | Apply a typeclass method to each field of a 'FieldRec'. This is a
-- -- specialization of 'rmapMethod'.
-- mapFields :: forall c ts. RecMapMethod c ElField ts
-- => (forall a. c a => a -> a) -> FieldRec ts -> FieldRec ts
-- mapFields f = rmapMethod @c g
-- where g :: c (PayloadType ElField t) => ElField t -> ElField t
-- g (Field x) = Field (f x)
-- {-# INLINE mapFields #-}

-- | Like 'rtraverseIn', but the function between functors may be
-- constrained.
Expand Down
2 changes: 1 addition & 1 deletion Data/Vinyl/Derived.hs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ getField :: ElField '(s,t) -> t
getField (Field x) = x

-- | Get the label name of an 'ElField'.
getLabel :: forall s t. ElField '(s,t) -> String
getLabel :: forall s t. KnownSymbol s => ElField '(s,t) -> String
getLabel (Field _) = symbolVal (Proxy::Proxy s)

-- | 'ElField' is isomorphic to a functor something like @Compose
Expand Down
8 changes: 5 additions & 3 deletions Data/Vinyl/Functor.hs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ import Foreign.Ptr (castPtr)
import Foreign.Storable
import GHC.Generics
import GHC.TypeLits
import GHC.Types (Type)
import Data.Vinyl.TypeLevel (Snd)

{- $introduction
This module provides functors and functor compositions
Expand Down Expand Up @@ -107,8 +107,10 @@ newtype Const (a :: *) (b :: k)
-- | A value with a phantom 'Symbol' label. It is not a
-- Haskell 'Functor', but it is used in many of the same places a
-- 'Functor' is used in vinyl.
data ElField (field :: (Symbol, Type)) where
Field :: KnownSymbol s => !t -> ElField '(s,t)
--
-- Morally: newtype ElField (s, t) = Field t
-- But GHC doesn't allow that
newtype ElField (t :: (Symbol, *)) = Field (Snd t)

deriving instance Eq t => Eq (ElField '(s,t))
deriving instance Ord t => Ord (ElField '(s,t))
Expand Down
45 changes: 28 additions & 17 deletions benchmarks/AccessorsBench.hs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import Control.Monad (unless)
import Criterion.Main
import GHC.Arr
import Data.Monoid (Endo(..))
import Data.Vinyl
import Data.Vinyl.Syntax ()
Expand All @@ -15,7 +16,8 @@ import System.Exit (exitFailure)

import qualified Bench.ARecOld as ARecOld
import Bench.ARec
import Bench.Rec
import Bench.SRec
import Bench.Rec

data HaskRec = HaskRec {
a0 :: Int,
Expand Down Expand Up @@ -126,6 +128,8 @@ main =
arec = mkARec 0
arecOld = ARecOld.mkARec 0
srec = toSRec newF
arr = listArray (0,0) [0]
smallArr = mkSmallArray (0 :: Int)
unless (rvalf #a15 arec == rvalf #a15 newF)
(do putStrLn "AFieldRec accessor disagrees with rvalf"
exitFailure)
Expand All @@ -145,15 +149,21 @@ main =
(do putStrLn "ARec record updates are inconsistent"
exitFailure)
defaultMain
[ {-bgroup "Update"
[ bgroup "primitives"
[ bench "pattern match" $ whnf a0 haskRec
, bench "array access" $ whnf (! 0) arr
, bench "small array access" $ whnf readSmallArray smallArr
]
{-bgroup "Update"
[ bench "Haskell Record" $ nf (a15 . updateHaskRec) haskRec
, bench "Rec" $ nf (rvalf #a15 . updateRec) newF
, bench "ARec" $ nf (rvalf #a15 . updateARec) arec
, bench "SRec" $ nf (rvalf #a15 . updateSRec) srec
]
, -}
bgroup "creating"
, bgroup "creating"
[ bench "vinyl record" $ whnf mkRec 0
, bench "toSRec" $ whnf mkToSRec 0
, bench "Old style ARec with toARec " $ whnf ARecOld.mkToARec 0
, bench "Old style ARec with toARecFast " $ whnf ARecOld.mkToARecFast 0
, bench "Old style ARec with arec " $ whnf ARecOld.mkARec 0
Expand All @@ -166,24 +176,25 @@ main =
{- , bench "strict haskell record" $ whnf sumSHaskRec shaskRec
, bench "unboxed strict haskell record" $ whnf sumUSHaskRec ushaskRec
-}
, bench "vinyl SRec" $ nf sumSRec srec
, bench "vinyl Rec" $ nf sumRec newF
, bench "vinyl ARec" $ nf sumARec arec
, bench "vinyl ARec Old" $ nf ARecOld.sumARec arecOld
]
, bgroup "FieldRec"
[ bench "a0" $ nf (rvalf #a0) newF
, bench "a4" $ nf (rvalf #a4) newF
, bench "a8" $ nf (rvalf #a8) newF
, bench "a12" $ nf (rvalf #a12) newF
, bench "a15" $ nf (rvalf #a15) newF
]
, bgroup "AFieldRec"
[ bench "a0" $ nf (rvalf #a0) arec
-- , bench "a4" $ nf (rvalf #a4) arec
-- , bench "a8" $ nf (rvalf #a8) arec
-- , bench "a12" $ nf (rvalf #a12) arec
, bench "a15" $ nf (rvalf #a15) arec
]
-- , bgroup "FieldRec"
-- [ bench "a0" $ nf (rvalf #a0) newF
-- , bench "a4" $ nf (rvalf #a4) newF
-- , bench "a8" $ nf (rvalf #a8) newF
-- , bench "a12" $ nf (rvalf #a12) newF
-- , bench "a15" $ nf (rvalf #a15) newF
-- ]
-- , bgroup "AFieldRec"
-- [ bench "a0" $ nf (rvalf #a0) arec
-- -- , bench "a4" $ nf (rvalf #a4) arec
-- -- , bench "a8" $ nf (rvalf #a8) arec
-- -- , bench "a12" $ nf (rvalf #a12) arec
-- , bench "a15" $ nf (rvalf #a15) arec
-- ]
{- , bgroup "SFieldRec"
[ bench "a0" $ nf (rvalf #a0) srec
-- , bench "a4" $ nf (rvalf #a4) srec
Expand Down
7 changes: 6 additions & 1 deletion benchmarks/Bench/ARec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE GADTs #-}

module Bench.ARec where
module Bench.ARec
( module Bench.ARec
, mkSmallArray
, readSmallArray
)
where

import Data.Vinyl
import Data.Vinyl.ARec.Internal
Expand Down
34 changes: 34 additions & 0 deletions benchmarks/Bench/SRec.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE OverloadedLabels #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE GADTs #-}

module Bench.SRec where

import Data.Vinyl.SRec
import Data.Vinyl

import Bench.Rec (Fields)


mkToSRec :: Int -> SRec ElField Fields
mkToSRec i= toSRec (Field i :& Field i :& Field i :& Field i :&
Field i :& Field i :& Field i :& Field i :&
Field i :& Field i :& Field i :& Field i :&
Field i :& Field i :& Field i :& Field 99 :&
RNil)


sumSRec :: SRec ElField Fields -> Int
sumSRec str =
get #a0 str + get #a1 str + get #a2 str + get #a3 str + get #a4 str
+ get #a5 str + get #a6 str + get #a7 str + get #a8 str
+ get #a9 str + get #a10 str + get #a11 str + get #a12 str
+ get #a13 str + get #a14 str + get #a15 str
where
get (label :: Label s) r =
case rget @'(s, Int) r of
Field v -> v
{-# INLINE get #-}
1 change: 1 addition & 0 deletions vinyl.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ benchmark accessors
main-is: AccessorsBench.hs
build-depends: base, criterion, tagged, vinyl, microlens
other-modules: Bench.ARec
other-modules: Bench.SRec
Bench.Rec
Bench.ARecOld
ghc-options: -O2
Expand Down

0 comments on commit 34c8305

Please sign in to comment.