boring-0.2.2/0000755000000000000000000000000007346545000011164 5ustar0000000000000000boring-0.2.2/ChangeLog.md0000644000000000000000000000164007346545000013336 0ustar0000000000000000# Revision history for boring ## 0.2.2 - Support GHC-8.6.5...9.10.1 ## 0.2.1 - Add instances for `SNat`, `SSymbol`, and `SChar` (singletons introduced in `base-4.18.0.0`) ## 0.2 - Make `boring` package dependency light. `fin`, `bin`, `ral`, `vec`, `dec`, `singleton-bool` instances are migrated to corresponding packages. Rest are migrated to `boring-instances` for now. - Data.Boring is `Trustworthy` - Add Generic derivation. Thanks to David Feuer. ## 0.1.3 - Allow `vec-0.3` - Add instances for `ral` and `bin` types. ## 0.1.2 - Add instances for 'Boring' instances for 'SBool', 'SNat' and 'LE'. - Add 'Boring (Dec a)', 'boringYes' and 'boringNo'. ## 0.1.1 - Add `GHC.Generics` instances - Add `:~~:` and `Coercion` instances ## 0.1 - `streams`, `constraints`, `generics-sop` instances. - Reversed dependency with `vec`, add `fin` instances. ## 0 - First version. Released on an unsuspecting world. boring-0.2.2/LICENSE0000644000000000000000000000276207346545000012200 0ustar0000000000000000Copyright (c) 2017, Oleg Grenrus All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Oleg Grenrus nor the names of other contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. boring-0.2.2/boring.cabal0000644000000000000000000000331607346545000013433 0ustar0000000000000000cabal-version: 2.2 name: boring version: 0.2.2 synopsis: Boring and Absurd types description: * @Boring@ types are isomorphic to @()@. . * @Absurd@ types are isomorphic to @Void@. . See [What does () mean in Haskell -answer by Conor McBride](https://stackoverflow.com/questions/33112439/what-does-mean-in-haskell/33115522#33115522) homepage: https://github.com/phadej/boring bug-reports: https://github.com/phadej/boring/issues license: BSD-3-Clause license-file: LICENSE author: Oleg Grenrus maintainer: Oleg.Grenrus copyright: (c) 2017-2021 Oleg Grenrus category: Data build-type: Simple extra-source-files: ChangeLog.md tested-with: GHC ==8.6.5 || ==8.8.4 || ==8.10.7 || ==9.0.2 || ==9.2.8 || ==9.4.8 || ==9.6.5 || ==9.8.2 || ==9.10.1 source-repository head type: git location: https://github.com/phadej/boring.git subdir: boring flag tagged description: You can disable the use of the `tagged` package using `-f-tagged`. . Disabling this is an unsupported configuration, but it may be useful for accelerating builds in sandboxes for expert users. default: True manual: True library exposed-modules: Data.Boring build-depends: base >=4.12.0.0 && <4.21 , transformers >=0.5.6.2 && <0.7 if impl(ghc <7.6) build-depends: ghc-prim if flag(tagged) build-depends: tagged >=0.8.6 && <0.9 other-extensions: CPP DefaultSignatures FlexibleContexts GADTs Trustworthy TypeOperators hs-source-dirs: src default-language: Haskell2010 boring-0.2.2/src/Data/0000755000000000000000000000000007346545000012624 5ustar0000000000000000boring-0.2.2/src/Data/Boring.hs0000644000000000000000000002607407346545000014411 0ustar0000000000000000{-# LANGUAGE CPP #-} {-# LANGUAGE DefaultSignatures #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE Trustworthy #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE EmptyCase #-} -- | 'Boring' and 'Absurd' classes. One approach. -- -- Different approach would be to have -- -- @ -- -- none-one-tons semiring -- data NOT = None | One | Tons -- -- type family Cardinality (a :: *) :: NOT -- -- class Cardinality a ~ None => Absurd a where ... -- class Cardinality a ~ One => Boring a where ... -- @ -- -- This would make possible to define more instances, e.g. -- -- @ -- instance (Mult (Cardinality a) (Cardinality b) ~ None) => Absurd (a, b) where ... -- @ -- -- === Functions -- -- Function is an exponential: -- -- @ -- Cardinality (a -> b) ~ Exponent (Cardinality b) (Cardinality a) -- @ -- -- or shortly @|a -> b| = |b| ^ |a|@. This gives us possible instances: -- -- * @|a| = 0 => |a -> b| = m ^ 0 = 1@, i.e. @'Absurd' a => 'Boring' (a -> b)@, or -- -- * @|b| = 1 => |a -> b| = 1 ^ n = 1@, i.e. @'Boring' b => 'Boring' (a -> b)@. -- -- Both instances are 'Boring', but we chose to define the latter. -- -- === Note about adding instances -- -- At this moment this module misses a lot of instances, -- please make a patch to add more. Especially, if the package is already -- in the transitive dependency closure. -- -- E.g. any possibly empty container @f@ has @'Absurd' a => 'Boring' (f a)@ -- module Data.Boring ( -- * Classes Boring (..), Absurd (..), -- ** Generic implementation GBoring, GAbsurd, -- * More interesting stuff vacuous, devoid, united, ) where import Prelude (Either (..), Functor (..), Maybe (..), const, (.)) import Control.Applicative (Const (..), (<$)) import Data.Functor.Compose (Compose (..)) import Data.Functor.Identity (Identity (..)) import Data.Functor.Product (Product (..)) import Data.Functor.Sum (Sum (..)) import Data.List.NonEmpty (NonEmpty (..)) import Data.Proxy (Proxy (..)) import GHC.Generics (Generic (..), K1 (..), M1 (..), Par1 (..), Rec1 (..), U1 (..), V1, (:*:) (..), (:+:) (..), (:.:) (..)) import qualified Data.Void as V import qualified Data.Coerce as Co import qualified Data.Type.Coercion as Co import qualified Data.Type.Equality as Eq import qualified Type.Reflection as Typeable #if MIN_VERSION_base(4,18,0) import qualified GHC.TypeLits as TypeLits import qualified GHC.TypeNats as TypeNats #endif #ifdef MIN_VERSION_tagged import Data.Tagged (Tagged (..)) #endif -- $setup -- >>> :set -XDeriveGeneric -- >>> import GHC.Generics (Generic) ------------------------------------------------------------------------------- -- Boring ------------------------------------------------------------------------------- -- | 'Boring' types which contains one thing, also -- 'boring'. There is nothing interesting to be gained by -- comparing one element of the boring type with another, -- because there is nothing to learn about an element of the -- boring type by giving it any of your attention. -- -- /Boring Law:/ -- -- @ -- 'boring' == x -- @ -- -- /Note:/ This is different class from @Default@. -- @Default@ gives you /some/ value, -- @Boring@ gives you an unique value. -- -- Also note, that we cannot have instances for e.g. -- 'Either', as both -- @('Boring' a, 'Absurd' b) => Either a b@ and -- @('Absurd' a, 'Boring' b) => Either a b@ would be valid instances. -- -- Another useful trick, is that you can rewrite computations with -- 'Boring' results, for example @foo :: Int -> ()@, __if__ you are sure -- that @foo@ is __total__. -- -- > {-# RULES "less expensive" foo = boring #-} -- -- That's particularly useful with equality ':~:' proofs. -- class Boring a where boring :: a default boring :: (Generic a, GBoring (Rep a)) => a boring = to gboring instance Boring () where boring = () instance Boring b => Boring (a -> b) where boring = const boring instance Boring (Proxy a) where boring = Proxy instance Boring a => Boring (Const a b) where boring = Const boring #ifdef MIN_VERSION_tagged instance Boring b => Boring (Tagged a b) where boring = Tagged boring #endif instance Boring a => Boring (Identity a) where boring = Identity boring instance Boring (f (g a)) => Boring (Compose f g a) where boring = Compose boring instance (Boring (f a), Boring (g a)) => Boring (Product f g a) where boring = Pair boring boring instance (Boring a, Boring b) => Boring (a, b) where boring = (boring, boring) instance (Boring a, Boring b, Boring c) => Boring (a, b, c) where boring = (boring, boring, boring) instance (Boring a, Boring b, Boring c, Boring d) => Boring (a, b, c, d) where boring = (boring, boring, boring, boring) instance (Boring a, Boring b, Boring c, Boring d, Boring e) => Boring (a, b, c, d, e) where boring = (boring, boring, boring, boring, boring) -- | Recall regular expressions, kleene star of empty regexp is epsilon! instance Absurd a => Boring [a] where boring = [] -- | @'Maybe' a = a + 1@, @0 + 1 = 1@. instance Absurd a => Boring (Maybe a) where boring = Nothing -- | Coercibility is 'Boring' too. instance Co.Coercible a b => Boring (Co.Coercion a b) where boring = Co.Coercion -- | Homogeneous type equality is 'Boring' too. instance a ~ b => Boring (a Eq.:~: b) where boring = Eq.Refl -- | Heterogeneous type equality is 'Boring' too. instance a Eq.~~ b => Boring (a Eq.:~~: b) where boring = Eq.HRefl instance Typeable.Typeable a => Boring (Typeable.TypeRep a) where boring = Typeable.typeRep #if MIN_VERSION_base(4,18,0) instance TypeLits.KnownChar n => Boring (TypeLits.SChar n) where boring = TypeLits.charSing instance TypeLits.KnownSymbol n => Boring (TypeLits.SSymbol n) where boring = TypeLits.symbolSing instance TypeNats.KnownNat n => Boring (TypeNats.SNat n) where boring = TypeNats.natSing #endif ------------------------------------------------------------------------------- -- Generics ------------------------------------------------------------------------------- instance Boring (U1 p) where boring = U1 instance Boring c => Boring (K1 i c p) where boring = K1 boring instance Boring (f p) => Boring (M1 i c f p) where boring = M1 boring instance (Boring (f p), Boring (g p)) => Boring ((f :*: g) p) where boring = boring :*: boring instance Boring p => Boring (Par1 p) where boring = Par1 boring instance Boring (f p) => Boring (Rec1 f p) where boring = Rec1 boring instance Boring (f (g p)) => Boring ((f :.: g) p) where boring = Comp1 boring ------------------------------------------------------------------------------- -- Absurd ------------------------------------------------------------------------------- -- | The 'Absurd' type is very exciting, because if somebody ever gives you a -- value belonging to it, you know that you are already dead and in Heaven and -- that anything you want is yours. -- -- Similarly as there are many 'Boring' sums, there are many 'Absurd' products, -- so we don't have 'Absurd' instances for tuples. class Absurd a where absurd :: a -> b default absurd :: (Generic a, GAbsurd (Rep a)) => a -> b absurd = gabsurd . from instance Absurd V.Void where absurd = V.absurd instance (Absurd a, Absurd b) => Absurd (Either a b) where absurd (Left a) = absurd a absurd (Right b) = absurd b instance Absurd a => Absurd (NonEmpty a) where absurd (x :| _) = absurd x instance Absurd a => Absurd (Identity a) where absurd = absurd . runIdentity instance Absurd (f (g a)) => Absurd (Compose f g a) where absurd = absurd . getCompose instance (Absurd (f a), Absurd (g a)) => Absurd (Sum f g a) where absurd (InL fa) = absurd fa absurd (InR ga) = absurd ga instance Absurd b => Absurd (Const b a) where absurd = absurd . getConst #ifdef MIN_VERSION_tagged instance Absurd a => Absurd (Tagged b a) where absurd = absurd . unTagged #endif ------------------------------------------------------------------------------- -- Generics ------------------------------------------------------------------------------- instance Absurd (V1 p) where absurd v = case v of {} instance Absurd c => Absurd (K1 i c p) where absurd = absurd . unK1 instance Absurd (f p) => Absurd (M1 i c f p) where absurd = absurd . unM1 instance (Absurd (f p), Absurd (g p)) => Absurd ((f :+: g) p) where absurd (L1 a) = absurd a absurd (R1 b) = absurd b instance Absurd p => Absurd (Par1 p) where absurd = absurd . unPar1 instance Absurd (f p) => Absurd (Rec1 f p) where absurd = absurd . unRec1 instance Absurd (f (g p)) => Absurd ((f :.: g) p) where absurd = absurd . unComp1 ------------------------------------------------------------------------------- -- More interesting stuff ------------------------------------------------------------------------------- -- | If 'Absurd' is uninhabited then any 'Functor' that holds only -- values of type 'Absurd' is holding no values. vacuous :: (Functor f, Absurd a) => f a -> f b vacuous = fmap absurd -- | There is a field for every type in the 'Absurd'. Very zen. -- -- @ -- 'devoid' :: 'Absurd' s => Over p f s s a b -- @ -- type Over p f s t a b = p a (f b) -> s -> f t devoid :: Absurd s => p a (f b) -> s -> f s devoid _ = absurd -- | We can always retrieve a 'Boring' value from any type. -- -- @ -- 'united' :: 'Boring' a => Lens' s a -- @ united :: (Boring a, Functor f) => (a -> f a) -> s -> f s united f v = v <$ f boring ------------------------------------------------------------------------------- -- default implementatiosn ------------------------------------------------------------------------------- -- | A helper class to implement 'Generic' derivation of 'Boring'. -- -- Technically we could do (avoiding @QuantifiedConstraints@): -- -- @ -- type GBoring f = (Boring (f V.Void), Functor f) -- -- gboring :: forall f x. GBoring f => f x -- gboring = vacuous (boring :: f V.Void) -- @ -- -- but separate class is cleaner. -- -- >>> data B2 = B2 () () deriving (Show, Generic) -- >>> instance Boring B2 -- >>> boring :: B2 -- B2 () () -- class GBoring f where gboring :: f a instance GBoring U1 where gboring = U1 instance GBoring f => GBoring (M1 i c f) where gboring = M1 gboring instance (GBoring f, GBoring g) => GBoring (f :*: g) where gboring = gboring :*: gboring -- There are two valid instances for GBoring (f :+: g), so we don't define -- either of them. instance Boring c => GBoring (K1 i c) where gboring = K1 boring -- | A helper class to implement of 'Generic' derivation of 'Absurd'. -- -- @ -- type GAbsurd f = (Absurd (f ()), Functor f) -- -- gabsurd :: forall f x y. GAbsurd f => f x -> y -- gabsurd = absurd . void -- @ -- class GAbsurd f where gabsurd :: f a -> b instance GAbsurd V1 where gabsurd x = case x of {} instance GAbsurd f => GAbsurd (M1 i c f) where gabsurd (M1 x) = gabsurd x instance Absurd c => GAbsurd (K1 i c) where gabsurd (K1 x) = absurd x instance (GAbsurd f, GAbsurd g) => GAbsurd (f :+: g) where gabsurd (L1 x) = gabsurd x gabsurd (R1 y) = gabsurd y -- There are two reasonable instances for GAbsurd (f :*: g), so we define neither