Skip to content

Commit 9efb1de

Browse files
committed
Add Lift instances for Data.Sequence
Add `Lift` instances for `Seq`, `ViewL`, and `ViewR`. The `Seq` instance tries to be a bit clever about the shape of the resulting tree and the size of the splice; everything else is straightforward.
1 parent f4aec7f commit 9efb1de

File tree

5 files changed

+85
-7
lines changed

5 files changed

+85
-7
lines changed

containers-tests/containers-tests.cabal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ common deps
3737
array >=0.4.0.0
3838
, base >=4.9.1 && <5
3939
, deepseq >=1.2 && <1.5
40+
, template-haskell
4041

4142
common test-deps
4243
import: deps

containers-tests/tests/seq-properties.hs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{-# LANGUAGE CPP #-}
22
{-# LANGUAGE PatternGuards #-}
3+
{-# LANGUAGE TemplateHaskell #-}
34

45
#include "containers.h"
56

@@ -41,11 +42,17 @@ import Test.QuickCheck.Poly (A, OrdA, B, OrdB, C)
4142
import Control.Monad.Zip (MonadZip (..))
4243
import Control.DeepSeq (deepseq)
4344
import Control.Monad.Fix (MonadFix (..))
45+
import Test.Tasty.HUnit
46+
import qualified Language.Haskell.TH.Syntax as TH
4447

4548

4649
main :: IO ()
4750
main = defaultMain $ testGroup "seq-properties"
48-
[ testProperty "fmap" prop_fmap
51+
[ test_lift
52+
#if MIN_VERSION_template_haskell(2,16,0)
53+
, test_liftTyped
54+
#endif
55+
, testProperty "fmap" prop_fmap
4956
, testProperty "(<$)" prop_constmap
5057
, testProperty "foldr" prop_foldr
5158
, testProperty "foldr'" prop_foldr'
@@ -911,11 +918,28 @@ instance Applicative M where
911918
Action m f <*> Action n x = Action (m+n) (f x)
912919

913920
instance Monad M where
914-
return x = Action 0 x
915921
Action m x >>= f = let Action n y = f x in Action (m+n) y
916922

917923
instance Foldable M where
918924
foldMap f (Action _ x) = f x
919925

920926
instance Traversable M where
921927
traverse f (Action n x) = Action n <$> f x
928+
929+
-- ----------
930+
--
931+
-- Unit tests
932+
--
933+
-- ----------
934+
935+
test_lift :: TestTree
936+
test_lift = testCase "lift" $ do
937+
(mempty :: Seq Int) @=? $([| $(TH.lift (fromList [] :: Seq Integer)) |])
938+
fromList [1..3 :: Int] @=? $([| $(TH.lift (fromList [1..3 :: Integer])) |])
939+
940+
#if MIN_VERSION_template_haskell(2,16,0)
941+
test_liftTyped :: TestTree
942+
test_liftTyped = testCase "liftTyped" $ do
943+
(mempty :: Seq Int) @=? $$([|| $$(TH.liftTyped (fromList [])) ||])
944+
fromList [1..3 :: Int] @=? $$([|| $$(TH.liftTyped (fromList [1..3])) ||])
945+
#endif

containers/changelog.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@
77
* Bump Cabal version for tests, and use `common` clauses to reduce
88
duplication.
99

10+
### New instances
11+
12+
* `Data.Sequence` now offers `Lift` instances for `Seq`, `ViewL`, and `ViewR`
13+
for use with Template Haskell.
14+
1015
## 0.6.5.1
1116

1217
### Bug fixes

containers/containers.cabal

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ source-repository head
3333

3434
Library
3535
default-language: Haskell2010
36-
build-depends: base >= 4.9.1 && < 5, array >= 0.4.0.0, deepseq >= 1.2 && < 1.5
36+
build-depends: base >= 4.9.1 && < 5, array >= 0.4.0.0, deepseq >= 1.2 && < 1.5, template-haskell
3737
hs-source-dirs: src
3838
ghc-options: -O2 -Wall -fwarn-incomplete-uni-patterns -fwarn-incomplete-record-updates
3939

containers/src/Data/Sequence/Internal.hs

Lines changed: 52 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,20 @@
44
#if __GLASGOW_HASKELL__
55
{-# LANGUAGE DeriveDataTypeable #-}
66
{-# LANGUAGE DeriveGeneric #-}
7+
{-# LANGUAGE DeriveLift #-}
78
{-# LANGUAGE StandaloneDeriving #-}
89
{-# LANGUAGE FlexibleInstances #-}
910
{-# LANGUAGE ScopedTypeVariables #-}
10-
{-# LANGUAGE TypeFamilies #-}
11+
{-# LANGUAGE TemplateHaskellQuotes #-}
1112
{-# LANGUAGE Trustworthy #-}
13+
{-# LANGUAGE TypeFamilies #-}
14+
{-# LANGUAGE TypeOperators #-}
1215
#endif
1316
#ifdef DEFINE_PATTERN_SYNONYMS
1417
{-# LANGUAGE PatternSynonyms #-}
1518
{-# LANGUAGE ViewPatterns #-}
1619
#endif
1720
{-# LANGUAGE PatternGuards #-}
18-
{-# LANGUAGE TypeOperators #-}
1921

2022
{-# OPTIONS_HADDOCK not-home #-}
2123
{-# OPTIONS_GHC -fno-warn-incomplete-uni-patterns #-}
@@ -223,8 +225,7 @@ import Text.Read (Lexeme(Ident), lexP, parens, prec,
223225
readPrec, readListPrec, readListPrecDefault)
224226
import Data.Data
225227
import Data.String (IsString(..))
226-
#endif
227-
#if __GLASGOW_HASKELL__
228+
import qualified Language.Haskell.TH.Syntax as TH
228229
import GHC.Generics (Generic, Generic1)
229230
#endif
230231

@@ -339,6 +340,41 @@ instance Sized (ForceBox a) where
339340
-- | General-purpose finite sequences.
340341
newtype Seq a = Seq (FingerTree (Elem a))
341342

343+
#ifdef __GLASGOW_HASKELL__
344+
-- | @since 0.7
345+
instance TH.Lift a => TH.Lift (Seq a) where
346+
# if MIN_VERSION_template_haskell(2,16,0)
347+
liftTyped t = [|| coerceFT z ||]
348+
# else
349+
lift t = [| coerceFT z |]
350+
# endif
351+
where
352+
-- We rebalance the sequence to use only 3-nodes before lifting its
353+
-- underlying finger tree. This should minimize the size and depth of the
354+
-- tree generated at run-time. It also reduces the size of the splice,
355+
-- but I don't know how that affects the size of the resulting Core once
356+
-- all the types are added.
357+
Seq ft = zipWith (flip const) (replicate (length t) ()) t
358+
359+
-- We remove the 'Elem' constructors to reduce the size of the splice
360+
-- and the number of types and coercions in the generated Core. Instead
361+
-- of, say,
362+
--
363+
-- Seq (Deep 3 (Two (Elem 1) (Elem 2)) EmptyT (One (Elem 3)))
364+
--
365+
-- we generate
366+
--
367+
-- coerceFT (Deep 3 (Two 1 2)) EmptyT (One 3)
368+
z :: FingerTree a
369+
z = coerce ft
370+
371+
-- | We use this to help the types work out for splices in the
372+
-- Lift instance. Things get a bit yucky otherwise.
373+
coerceFT :: FingerTree a -> Seq a
374+
coerceFT = coerce
375+
376+
#endif
377+
342378
instance Functor Seq where
343379
fmap = fmapSeq
344380
#ifdef __GLASGOW_HASKELL__
@@ -974,6 +1010,8 @@ deriving instance Generic1 FingerTree
9741010

9751011
-- | @since 0.6.1
9761012
deriving instance Generic (FingerTree a)
1013+
1014+
deriving instance TH.Lift a => TH.Lift (FingerTree a)
9771015
#endif
9781016

9791017
instance Sized a => Sized (FingerTree a) where
@@ -1165,6 +1203,8 @@ deriving instance Generic1 Digit
11651203

11661204
-- | @since 0.6.1
11671205
deriving instance Generic (Digit a)
1206+
1207+
deriving instance TH.Lift a => TH.Lift (Digit a)
11681208
#endif
11691209

11701210
foldDigit :: (b -> b -> b) -> (a -> b) -> Digit a -> b
@@ -1266,6 +1306,8 @@ deriving instance Generic1 Node
12661306

12671307
-- | @since 0.6.1
12681308
deriving instance Generic (Node a)
1309+
1310+
deriving instance TH.Lift a => TH.Lift (Node a)
12691311
#endif
12701312

12711313
foldNode :: (b -> b -> b) -> (a -> b) -> Node a -> b
@@ -2131,6 +2173,9 @@ deriving instance Generic1 ViewL
21312173

21322174
-- | @since 0.5.8
21332175
deriving instance Generic (ViewL a)
2176+
2177+
-- | @since 0.7
2178+
deriving instance TH.Lift a => TH.Lift (ViewL a)
21342179
#endif
21352180

21362181
instance Functor ViewL where
@@ -2195,6 +2240,9 @@ deriving instance Generic1 ViewR
21952240

21962241
-- | @since 0.5.8
21972242
deriving instance Generic (ViewR a)
2243+
2244+
-- | @since 0.7
2245+
deriving instance TH.Lift a => TH.Lift (ViewR a)
21982246
#endif
21992247

22002248
instance Functor ViewR where

0 commit comments

Comments
 (0)