OneTuple 0.2.2.1 → 0.4.3
raw patch · 7 files changed
Files
- Changelog.md +31/−1
- OneTuple.cabal +86/−19
- src/Data/Tuple/OneTuple.hs +18/−79
- src/Data/Tuple/Solo.hs +200/−0
- src/Data/Tuple/Solo/TH.hs +44/−0
- test/instances.hs +74/−0
- test/th.hs +8/−0
Changelog.md view
@@ -1,4 +1,34 @@-# next+# 0.4.3++- Use automatic flags for compatibility conditionals++# 0.4.1.1++- Support GHC-7.2 and GHC-7.0.++# 0.4.1++- Mark `MkSolo` pattern synonym as `COMPLETE`++# 0.4++- Rename constructor to `MkSolo` as in `base-4.17`.+ The compatibility pattern synonym is provided.+- Add `Foldable1 Solo` instance++# 0.3.1++- Add `Data.Tuple.Solo.TH` with `tupE` using `Solo` from this package+- Add `Hashable` and `Hashable1` instances+- Drop GHC-7.0 and GHC-7.2 support++# 0.3++- Rename `OneTuple` to `Solo`+- Add `Typeable`, `Data`, `MonadZip`, `Eq1`, `Ord1`, `Show1`, `Read1`,+ `Generic` and `Generic1` instances++# 0.2.2.1 - Compatible with GHC-8.6
OneTuple.cabal view
@@ -1,14 +1,16 @@-cabal-version: >=1.10+cabal-version: 1.12 name: OneTuple-version: 0.2.2.1+version: 0.4.3 synopsis: Singleton Tuple category: Data description:- This package provides a singleton tuple data type+ This package is a compatibility package for a singleton data type .- > data OneTuple a = OneTuple a+ > data Solo a = MkSolo a . Note: it's not a @newtype@+ .+ @Solo@ is available in @base-4.16@ (GHC-9.2). copyright: (c) John Dorsey 2008 license: BSD3@@ -20,18 +22,17 @@ stability: experimental build-type: Simple tested-with:- GHC ==7.0.4- || ==7.2.2- || ==7.4.2- || ==7.6.3- || ==7.8.4- || ==7.10.3- || ==8.0.2- || ==8.2.2- || ==8.4.4- || ==8.6.5- || ==8.8.3- || ==8.10.1+ GHC ==8.6.5+ || ==8.8.4+ || ==8.10.7+ || ==9.0.2+ || ==9.2.8+ || ==9.4.8+ || ==9.6.4+ || ==9.8.6+ || ==9.10.2+ || ==9.12.2+ || ==9.14.1 extra-source-files: Changelog.md @@ -39,11 +40,77 @@ type: git location: https://github.com/phadej/OneTuple.git +flag base-ge-4-15+ description: @base >=4.15@ (GHC-9.0)+ default: True+ manual: False++flag base-ge-4-16+ description: @base >=4.16@ (GHC-9.2)+ default: True+ manual: False+ library default-language: Haskell98- exposed-modules: Data.Tuple.OneTuple+ exposed-modules:+ Data.Tuple.OneTuple+ Data.Tuple.Solo+ Data.Tuple.Solo.TH+ hs-source-dirs: src- build-depends: base >=4.3 && <4.15+ build-depends:+ base >=4.12 && <4.23+ , template-haskell + if flag(base-ge-4-15)+ build-depends: ghc-prim++ else+ build-depends: hashable >=1.3.5.0 && <1.6++ if !flag(base-ge-4-15)+ build-depends: foldable1-classes-compat >=0.1 && <0.2++ if !flag(base-ge-4-16)+ build-depends: base-orphans >=0.8.6++ -- flag selection forcing conditionals+ if flag(base-ge-4-15)+ build-depends: base >=4.15++ else+ build-depends: base <4.15++ if flag(base-ge-4-16)+ build-depends: base >=4.16++ else+ build-depends: base <4.16++test-suite instances+ type: exitcode-stdio-1.0+ default-language: Haskell98+ hs-source-dirs: test+ main-is: instances.hs+ build-depends:+ base+ , hashable+ , OneTuple+ if !impl(ghc >=8.0)- build-depends: semigroups >=0.18.4 && <0.20+ build-depends:+ semigroups+ , transformers+ , transformers-compat++ if !impl(ghc >=9.6)+ build-depends: foldable1-classes-compat >=0.1 && <0.2++test-suite th+ type: exitcode-stdio-1.0+ default-language: Haskell98+ hs-source-dirs: test+ main-is: th.hs+ build-depends:+ base+ , OneTuple
src/Data/Tuple/OneTuple.hs view
@@ -1,85 +1,24 @@--- |OneTuple fills the /tuple gap/ with a singleton tuple.------ OneTuple /does not support/ the usual parenthesized tuple syntax.------ OneTuple------ * has the expected laziness properties------ * can be pattern-matched------ * ships with instances for several standard type classes,--- including all those supported by H98-standard tuples+{-# LANGUAGE PatternSynonyms #-}+-- | This is a module to help migration from @OneTuple@ to @Solo@.+-- Migrate to use "Data.Tuple" from @base-4.16@ or "Data.Tuple.Solo" with all GHCs. ----- * requires no language extensions, except for hierarchical modules--module Data.Tuple.OneTuple (OneTuple(OneTuple), only) where--import Control.Applicative (Applicative (..))-import Control.Monad (ap)-import Control.Monad.Fix (MonadFix (..))-import Data.Foldable (Foldable (..))-import Data.Ix (Ix (..))-import Data.Monoid (Monoid (..))-import Data.Semigroup (Semigroup (..))-import Data.Traversable (Traversable (..))---- |OneTuple is the singleton tuple data type.-data OneTuple a- = OneTuple a -- ^ singleton tuple constructor- deriving (Eq,Ord,Bounded,Show,Read)---- |The 'only' function extracts the OneTuple's only member.--- (Compare to 'fst' and 'snd'.)-only :: OneTuple a -- ^ takes a singleton tuple argument- -> a -- ^ returns the only element in the tuple-only (OneTuple x) = x--instance (Enum a) => Enum (OneTuple a) where- succ = fmap succ- pred = fmap pred- toEnum = pure . toEnum- fromEnum (OneTuple x) = fromEnum x--instance (Ix a) => Ix (OneTuple a) where- range (OneTuple x, OneTuple y) = map OneTuple (range (x,y))- index (OneTuple x, OneTuple y) (OneTuple z) = index (x,y) z- inRange (OneTuple x, OneTuple y) (OneTuple z) = inRange (x,y) z--instance Foldable OneTuple where- fold (OneTuple m) = m- foldMap f (OneTuple x) = f x- foldr f b (OneTuple x) = f x b- foldl f a (OneTuple x) = f a x- foldr1 _f (OneTuple x) = x- foldl1 _f (OneTuple x) = x--instance Traversable OneTuple where- traverse f (OneTuple x) = fmap OneTuple (f x)- sequenceA (OneTuple x) = fmap OneTuple x--instance Functor OneTuple where- fmap f (OneTuple x) = OneTuple (f x)--instance Applicative OneTuple where- pure = OneTuple-- OneTuple f <*> OneTuple x = OneTuple (f x)- _ *> x = x- x <* _ = x+-- The pattern synonym is provided for GHCs supporting pattern synonyms (7.8+)+module Data.Tuple.OneTuple+{-# DEPRECATED "Use Data.Tuple.Solo" #-}+(+ OneTuple,+ pattern OneTuple,+ only,+) where -instance Monad OneTuple where- return = pure- (>>) = (*>)- (OneTuple x) >>= f = f x+import Data.Tuple.Solo -instance (Semigroup a) => Semigroup (OneTuple a) where- OneTuple x <> OneTuple y = OneTuple (x <> y)+type OneTuple = Solo -instance (Monoid a) => Monoid (OneTuple a) where- mempty = OneTuple mempty- mappend (OneTuple x) (OneTuple y) = OneTuple (mappend x y)+only :: OneTuple a -> a+only = getSolo -instance MonadFix OneTuple where- mfix f = let a = f (only a) in a+pattern OneTuple :: a -> Solo a+pattern OneTuple a = MkSolo a +{-# COMPLETE OneTuple #-}
+ src/Data/Tuple/Solo.hs view
@@ -0,0 +1,200 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE PatternSynonyms #-}+{-# LANGUAGE Safe #-}++-- | 'Solo' fills the /tuple gap/ with a singleton tuple.+--+-- 'Solo' /does not support/ the usual parenthesized tuple syntax.+--+-- 'Solo'+--+-- * has the expected laziness properties+--+-- * can be pattern-matched+--+-- * ships with instances for several standard type classes,+-- including all those supported by H98-standard tuples+--+-- * requires no language extensions, except for hierarchical modules+--+-- Note: on GHC-9.0 'getSolo' is not a record selector.++module Data.Tuple.Solo (+ Solo(MkSolo,Solo),+ getSolo,+) where++#ifdef MIN_VERSION_base_orphans+import Data.Orphans ()+#endif++#if MIN_VERSION_base(4,18,0)+import GHC.Tuple (Solo (MkSolo, Solo), getSolo)+++#elif MIN_VERSION_base(4,16,0)+import GHC.Tuple (Solo (Solo), getSolo)++pattern MkSolo :: a -> Solo a+pattern MkSolo a = Solo a++{-# COMPLETE MkSolo #-}++#elif MIN_VERSION_base(4,15,0)+import GHC.Tuple (Solo (Solo))++-- | The 'getSolo' function extracts the Solo's getSolo member.+getSolo :: Solo a -> a+getSolo (Solo x) = x++pattern MkSolo :: a -> Solo a+pattern MkSolo a = Solo a++{-# COMPLETE MkSolo #-}++-- !MIN_VERSION_base(4,15,0)+#else++import Control.Applicative (Applicative (..))+import Control.Monad (ap)+import Control.Monad.Fix (MonadFix (..))+import Data.Data (Data)+import Data.Foldable (Foldable (..))+import Data.Ix (Ix (..))+import Data.List.NonEmpty (NonEmpty (..))+import Data.Monoid (Monoid (..))+import Data.Semigroup (Semigroup (..))+import Data.Traversable (Traversable (..))+import Data.Typeable (Typeable)++import qualified Data.Foldable1 as F1++import Data.Functor.Classes (Eq1 (..), Ord1 (..), Show1 (..), Read1 (..))++#if !(MIN_VERSION_base(4,15,0))+import Data.Hashable (Hashable (..))+import Data.Hashable.Lifted (Hashable1 (..), hashWithSalt1)+#endif++import Data.Functor.Classes (readData, readUnaryWith, liftReadListDefault, liftReadListPrecDefault)+import GHC.Generics (Generic, Generic1)+import Control.Monad.Zip (MonadZip (..))++-- | Solo is the singleton tuple data type.+data Solo a = MkSolo { getSolo :: a }+ deriving+ ( Eq,Ord,Bounded,Read,Typeable,Data+ , Generic+ , Generic1+ )++pattern Solo :: a -> Solo a+pattern Solo a = MkSolo a+{-# COMPLETE Solo #-}+++instance Show a => Show (Solo a) where+ showsPrec d (MkSolo x) = showParen (d > 10) $+ showString "MkSolo " . showsPrec 11 x++instance (Enum a) => Enum (Solo a) where+ succ = fmap succ+ pred = fmap pred+ toEnum = pure . toEnum+ fromEnum (MkSolo x) = fromEnum x++instance (Ix a) => Ix (Solo a) where+ range (MkSolo x, MkSolo y) = map MkSolo (range (x,y))+ index (MkSolo x, MkSolo y) (MkSolo z) = index (x,y) z+ inRange (MkSolo x, MkSolo y) (MkSolo z) = inRange (x,y) z++instance Foldable Solo where+ fold (MkSolo m) = m+ foldMap f (MkSolo x) = f x+ foldr f b (MkSolo x) = f x b+ foldl f a (MkSolo x) = f a x+ foldr1 _f (MkSolo x) = x+ foldl1 _f (MkSolo x) = x++ -- TODO: add rest of the methods+ null _ = False+ length _ = 1++ maximum = getSolo+ minimum = getSolo+ sum = getSolo+ product = getSolo++ toList (MkSolo a) = [a]++-- | @since 0.4+instance F1.Foldable1 Solo where+ foldMap1 f (MkSolo y) = f y+ toNonEmpty (MkSolo x) = x :| []+ minimum (MkSolo x) = x+ maximum (MkSolo x) = x+ head (MkSolo x) = x+ last (MkSolo x) = x++instance Traversable Solo where+ traverse f (MkSolo x) = fmap MkSolo (f x)+ sequenceA (MkSolo x) = fmap MkSolo x++instance Functor Solo where+ fmap f (MkSolo x) = MkSolo (f x)++instance Applicative Solo where+ pure = MkSolo++ MkSolo f <*> MkSolo x = MkSolo (f x)+ _ *> x = x+ x <* _ = x++ liftA2 f (Solo x) (Solo y) = Solo (f x y)++instance Monad Solo where+ return = pure+ (>>) = (*>)+ MkSolo x >>= f = f x++instance Semigroup a => Semigroup (Solo a) where+ MkSolo x <> MkSolo y = MkSolo (x <> y)++instance Monoid a => Monoid (Solo a) where+ mempty = MkSolo mempty+ mappend (MkSolo x) (MkSolo y) = MkSolo (mappend x y)++instance MonadFix Solo where+ mfix f = let a = f (getSolo a) in a++instance MonadZip Solo where+ mzipWith f (MkSolo a) (MkSolo b) = MkSolo (f a b)++instance Eq1 Solo where+ liftEq eq (MkSolo a) (MkSolo b) = a `eq` b++instance Ord1 Solo where+ liftCompare cmp (MkSolo a) (MkSolo b) = cmp a b++instance Read1 Solo where+ liftReadPrec rp _ = readData (readUnaryWith rp "MkSolo" MkSolo)++ liftReadListPrec = liftReadListPrecDefault+ liftReadList = liftReadListDefault++instance Show1 Solo where+ liftShowsPrec sp _ d (MkSolo x) = showParen (d > 10) $+ showString "MkSolo " . sp 11 x+#endif++#if !(MIN_VERSION_base(4,15,0))+-- | @since 0.3.1+instance Hashable a => Hashable (Solo a) where+ hashWithSalt = hashWithSalt1++-- | @since 0.3.1+instance Hashable1 Solo where+ liftHashWithSalt h salt (MkSolo a) = h salt a+#endif
+ src/Data/Tuple/Solo/TH.hs view
@@ -0,0 +1,44 @@+{-# LANGUAGE CPP #-}+#if __GLASGOW_HASKELL__ >= 800+{-# LANGUAGE TemplateHaskellQuotes #-}+#endif+-- | This module provides TH helpers,+-- which use 'Solo' from this package, for 1-tuples.+module Data.Tuple.Solo.TH (+ tupE,+) where+++#if MIN_VERSION_template_haskell(2,17,0)+import Language.Haskell.TH (tupE)+#else+import Data.Tuple.Solo++import qualified Language.Haskell.TH as TH+import qualified Language.Haskell.TH.Syntax as TH++makeTup :: [TH.Exp] -> TH.Exp+makeTup [x] = TH.AppE (TH.ConE soloConName) x+#if MIN_VERSION_template_haskell(2,16,0)+makeTup xs = TH.TupE (map Just xs)+#else+makeTup xs = TH.TupE xs+#endif++soloConName :: TH.Name+#if __GLASGOW_HASKELL__ >= 800+soloConName = 'Solo+#else+#ifndef CURRENT_PACKAGE_KEY +#error "CURRENT_PACKAGE_KEY undefined"+#endif++soloConName = TH.mkNameG_d CURRENT_PACKAGE_KEY "Data.Tuple.Solo" "MkSolo"+#endif++tupE :: Monad m => [m TH.Exp] -> m TH.Exp+tupE xs = do+ xs' <- sequence xs+ return (makeTup xs')+#endif+
+ test/instances.hs view
@@ -0,0 +1,74 @@+{-# LANGUAGE CPP #-}+{-# OPTIONS_GHC -Wincomplete-patterns -Werror=incomplete-patterns #-}+{-# OPTIONS_GHC -fwarn-incomplete-patterns -Werror #-}+module Main where++import Control.Applicative (Applicative (..))+import Control.Monad.Fix (MonadFix (..))+import Data.Data (Data)+import Data.Foldable (Foldable (..))+import Data.Foldable1 (Foldable1)+import Data.Functor.Classes (Eq1, Ord1, Read1, Show1)+import Data.Hashable (Hashable)+import Data.Hashable.Lifted (Hashable1)+import Data.Ix (Ix)+import Data.Monoid (Monoid (..))+import Data.Semigroup (Semigroup (..))+import Data.Traversable (Traversable (..))++#if MIN_VERSION_base(4,4,0)+import Control.Monad.Zip (MonadZip (..))+#endif++import Data.Tuple.Solo (Solo (..))++main :: IO ()+main = putStrLn "works"++-------------------------------------------------------------------------------+-- pattern match+-------------------------------------------------------------------------------++match :: Solo a -> a+match (MkSolo x) = x++-------------------------------------------------------------------------------+-- Instances+-------------------------------------------------------------------------------++tup1 :: Solo Char+tup1 = MkSolo 'x'++tup2 :: Solo String+tup2 = MkSolo "test"++hasEq :: Eq a => a -> a; hasEq x = x; testEq = hasEq tup1+hasOrd :: Ord a => a -> a; hasOrd x = x; testOrd = hasOrd tup1+hasBounded :: Bounded a => a -> a; hasBounded x = x; testBounded = hasBounded tup1+hasEnum :: Enum a => a -> a; hasEnum x = x; testEnum = hasEnum tup1+hasShow :: Show a => a -> a; hasShow x = x; testShow = hasShow tup1+hasRead :: Read a => a -> a; hasRead x = x; testRead = hasRead tup1+hasIx :: Ix a => a -> a; hasIx x = x; testIx = hasIx tup1++hasMonoid :: Monoid a => a -> a; hasMonoid x = x; testMonoid = hasMonoid tup2+hasSemigroup :: Semigroup a => a -> a; hasSemigroup x = x; testSemigroup = hasSemigroup tup2++hasData :: Data a => a -> a; hasData x = x; testData = hasData tup2++hasFunctor :: Functor f => f a -> f a; hasFunctor x = x; testFunctor = hasFunctor tup1+hasFoldable :: Foldable f => f a -> f a; hasFoldable x = x; testFoldable = hasFoldable tup1+hasFoldable1 :: Foldable1 f => f a -> f a; hasFoldable1 x = x; testFoldable1 = hasFoldable1 tup1+hasTraversable :: Traversable f => f a -> f a; hasTraversable x = x; testTraversable = hasTraversable tup1+hasApplicative :: Applicative f => f a -> f a; hasApplicative x = x; testApplicative = hasApplicative tup1+hasMonad :: Monad f => f a -> f a; hasMonad x = x; testMonad = hasMonad tup1+hasMonadFix :: MonadFix f => f a -> f a; hasMonadFix x = x; testMonadFix = hasMonadFix tup1++hasMonadZip :: MonadZip f => f a -> f a; hasMonadZip x = x; testMonadZip = hasMonadZip tup1++hasEq1 :: Eq1 f => f a -> f a; hasEq1 x = x; testEq1 = hasEq1 tup1+hasOrd1 :: Ord1 f => f a -> f a; hasOrd1 x = x; testOrd1 = hasOrd1 tup1+hasShow1 :: Show1 f => f a -> f a; hasShow1 x = x; testShow1 = hasShow1 tup1+hasRead1 :: Read1 f => f a -> f a; hasRead1 x = x; testRead1 = hasRead1 tup1++hasHashable :: Hashable a => a -> a; hasHashable x = x; testHashable = hasHashable tup1+hasHashable1 :: Hashable1 f => f a -> f a; hasHashable1 x = x; testHashable1 = hasHashable1 tup1
+ test/th.hs view
@@ -0,0 +1,8 @@+{-# LANGUAGE TemplateHaskell #-}+module Main where++import Data.Tuple.Solo+import Data.Tuple.Solo.TH (tupE)++main :: IO ()+main = print $ MkSolo 'x' == $(tupE [[| 'x' |]])