flay 0.2 → 0.3
raw patch · 7 files changed
+98/−101 lines, 7 filesdep +transformersdep −ghc-primPVP ok
version bump matches the API change (PVP)
Dependencies added: transformers
Dependencies removed: ghc-prim
API changes (from Hackage documentation)
- Flay: class GRecord (a :: * -> *)
- Flay: class Record a
- Flay: instance (Flay.GRecord l, Flay.GRecord r) => Flay.GRecord (l GHC.Generics.:*: r)
- Flay: instance (GHC.Generics.Generic a, Flay.GRecord (GHC.Generics.Rep a)) => Flay.Record a
- Flay: instance Flay.GRecord (GHC.Generics.K1 r x)
- Flay: instance Flay.GRecord GHC.Generics.U1
- Flay: instance Flay.GRecord x => Flay.GRecord (GHC.Generics.M1 i j x)
- Flay: instance forall k (c :: k -> GHC.Types.Constraint) (a :: k) r (f :: k -> *) (g :: k -> *). c a => Flay.GFlay' c (GHC.Generics.K1 r (f a)) (GHC.Generics.K1 r (g a)) f g
- Flay: instance forall k (c :: k -> GHC.Types.Constraint) (f :: k -> GHC.Types.*) (g :: k -> GHC.Types.*). Flay.GFlay' c GHC.Generics.V1 GHC.Generics.V1 f g
- Flay: instance forall k (c :: k -> GHC.Types.Constraint) (s :: GHC.Types.* -> *) (t :: GHC.Types.* -> *) (f :: k -> GHC.Types.*) (g :: k -> GHC.Types.*) i (j :: GHC.Generics.Meta). Flay.GFlay' c s t f g => Flay.GFlay' c (GHC.Generics.M1 i j s) (GHC.Generics.M1 i j t) f g
- Flay: instance forall k (c :: k -> GHC.Types.Constraint) (sl :: GHC.Types.* -> *) (tl :: GHC.Types.* -> *) (f :: k -> GHC.Types.*) (g :: k -> GHC.Types.*) (sr :: GHC.Types.* -> *) (tr :: GHC.Types.* -> *). (Flay.GFlay' c sl tl f g, Flay.GFlay' c sr tr f g) => Flay.GFlay' c (sl GHC.Generics.:*: sr) (tl GHC.Generics.:*: tr) f g
- Flay: instance forall k (c :: k -> GHC.Types.Constraint) (sl :: GHC.Types.* -> *) (tl :: GHC.Types.* -> *) (f :: k -> GHC.Types.*) (g :: k -> GHC.Types.*) (sr :: GHC.Types.* -> *) (tr :: GHC.Types.* -> *). (Flay.GFlay' c sl tl f g, Flay.GFlay' c sr tr f g) => Flay.GFlay' c (sl GHC.Generics.:+: sr) (tl GHC.Generics.:+: tr) f g
- Flay: instance forall k s t (c :: k -> GHC.Types.Constraint) (f :: k -> GHC.Types.*) (g :: k -> GHC.Types.*). (GHC.Generics.Generic s, GHC.Generics.Generic t, Flay.GFlay' c (GHC.Generics.Rep s) (GHC.Generics.Rep t) f g) => Flay.GFlay c s t f g
+ Flay: instance forall k s t (c :: k -> GHC.Types.Constraint) (f :: k -> *) (g :: k -> *). (GHC.Generics.Generic s, GHC.Generics.Generic t, Flay.GFlay' c (GHC.Generics.Rep s) (GHC.Generics.Rep t) f g) => Flay.GFlay c s t f g
+ Flay: instance forall k1 k2 (c :: k2 -> GHC.Types.Constraint) (a :: k2) r (f :: k2 -> *) (g :: k2 -> *). c a => Flay.GFlay' c (GHC.Generics.K1 r (f a)) (GHC.Generics.K1 r (g a)) f g
+ Flay: instance forall k1 k2 (c :: k2 -> GHC.Types.Constraint) (f :: k2 -> *) (g :: k2 -> *). Flay.GFlay' c GHC.Generics.V1 GHC.Generics.V1 f g
+ Flay: instance forall k1 k2 (c :: k2 -> GHC.Types.Constraint) (s :: k1 -> *) (t :: k1 -> *) (f :: k2 -> *) (g :: k2 -> *) i (j :: GHC.Generics.Meta). Flay.GFlay' c s t f g => Flay.GFlay' c (GHC.Generics.M1 i j s) (GHC.Generics.M1 i j t) f g
+ Flay: instance forall k1 k2 (c :: k2 -> GHC.Types.Constraint) (sl :: k1 -> *) (tl :: k1 -> *) (f :: k2 -> *) (g :: k2 -> *) (sr :: k1 -> *) (tr :: k1 -> *). (Flay.GFlay' c sl tl f g, Flay.GFlay' c sr tr f g) => Flay.GFlay' c (sl GHC.Generics.:*: sr) (tl GHC.Generics.:*: tr) f g
+ Flay: instance forall k1 k2 (c :: k2 -> GHC.Types.Constraint) (sl :: k1 -> *) (tl :: k1 -> *) (f :: k2 -> *) (g :: k2 -> *) (sr :: k1 -> *) (tr :: k1 -> *). (Flay.GFlay' c sl tl f g, Flay.GFlay' c sr tr f g) => Flay.GFlay' c (sl GHC.Generics.:+: sr) (tl GHC.Generics.:+: tr) f g
+ Flay: trivialize :: forall c s t f g. Flay c s t f g -> Flay Trivial s t f g
- Flay: class Flayable1 (c :: k -> Constraint) (r :: (k -> *) -> *) where flay1 = gflay
+ Flay: class Flayable1 (c :: k -> Constraint) (r :: (k -> *) -> *)
- Flay: data Dict (a :: Constraint) :: Constraint -> *
+ Flay: data Dict a :: Constraint -> *
- Flay: trivial :: (Applicative m, Flayable Trivial s t f g) => (forall a. Trivial a => f a -> m (g a)) -> s -> m t
+ Flay: trivial :: forall m s t f g. (Applicative m, Flayable Trivial s t f g) => (forall a. Trivial a => f a -> m (g a)) -> s -> m t
- Flay: trivial' :: forall m s t f g. Applicative m => Flay Trivial s t f g -> (forall a. Trivial a => f a -> m (g a)) -> s -> m t
+ Flay: trivial' :: forall m c s t f g. Applicative m => Flay c s t f g -> (forall a. Trivial a => f a -> m (g a)) -> s -> m t
- Flay: trivial1 :: (Applicative m, Flayable1 Trivial r) => (forall a. Trivial a => f a -> m (g a)) -> (r f) -> m (r g)
+ Flay: trivial1 :: forall m f g r. (Applicative m, Flayable1 Trivial r) => (forall a. Trivial a => f a -> m (g a)) -> (r f) -> m (r g)
- Flay: unsafeZip :: forall c s0 s1 t0 t1 f g h. Record s0 => (Flay c s0 t0 f (Const ())) -> (Flay c s1 t1 g h) -> (forall x. Dict (c x) -> f x -> g x -> h x) -> s0 -> s1 -> t1
+ Flay: unsafeZip :: forall c s1 s2 t1 t2 t3 f g h m. (Monad m, Typeable f) => (Flay Typeable s1 t1 f (Const ())) -> (Flay Typeable s2 t2 g (Product f g)) -> (Flay c t2 t3 (Product f g) h) -> (forall x. Dict (c x) -> f x -> g x -> m (h x)) -> s1 -> s2 -> m (Maybe t3)
- Flay: zip :: (Record s0, Flayable c s0 t0 f (Const ()), Flayable c s1 t1 g h) => (forall x. Dict (c x) -> f x -> g x -> h x) -> s0 -> s1 -> t1
+ Flay: zip :: (Monad m, Typeable f, Flayable Typeable s1 t1 f (Const ()), Flayable Typeable s2 t2 g (Product f g), Flayable c t2 t3 (Product f g) h) => (forall x. Dict (c x) -> f x -> g x -> m (h x)) -> s1 -> s2 -> m (Maybe t3)
- Flay: zip1 :: (Record (s f), Flayable1 c s) => (forall x. Dict (c x) -> f x -> g x -> h x) -> s f -> s g -> s h
+ Flay: zip1 :: (Monad m, Typeable f, Flayable1 c s, Flayable1 Typeable s) => (forall x. Dict (c x) -> f x -> g x -> m (h x)) -> s f -> s g -> m (Maybe (s h))
Files
- CHANGELOG.md +12/−0
- default.nix +1/−2
- flay.cabal +2/−2
- pkg.nix +3/−3
- release.nix +6/−24
- shell.nix +1/−2
- src/Flay.hs +73/−68
CHANGELOG.md view
@@ -1,3 +1,15 @@+# Version 0.3++* `zip`, `zip1` and `unsafeZip` now take a monadic pairing function, and return+ `Maybe` where `Nothing` happens in the target indexes do not match.++* Added `trivialize`.++* Generalized type of `trivial'`.++* Remove `Record` and `GRecord`.++ # Version 0.2 * BREAKING CHANGE: The `m` parameter in in `Flay` and `Flayable` has been
default.nix view
@@ -1,2 +1,1 @@-{ compiler ? "ghc822" }:-(import ./release.nix {}).${compiler}.flay+(import ./release.nix {}).flay
flay.cabal view
@@ -1,5 +1,5 @@ name: flay-version: 0.2+version: 0.3 author: Renzo Carbonara maintainer: renλren!zone copyright: Renzo Carbonara 2017@@ -28,7 +28,7 @@ build-depends: base >=4.9 && <5.0, constraints,- ghc-prim+ transformers test-suite tests default-language: Haskell2010
pkg.nix view
@@ -1,10 +1,10 @@-{ mkDerivation, base, constraints, ghc-prim, stdenv, tasty, tasty-quickcheck+{ mkDerivation, base, constraints, stdenv, tasty, tasty-quickcheck, transformers }: mkDerivation { pname = "flay";- version = "0.2";+ version = "0.3"; src = ./.;- libraryHaskellDepends = [ base constraints ghc-prim ];+ libraryHaskellDepends = [ base constraints transformers ]; testHaskellDepends = [ base tasty tasty-quickcheck ]; homepage = "https://github.com/k0001/flay"; description = "Work on your datatype without knowing its shape nor its contents";
release.nix view
@@ -1,30 +1,12 @@-{ nixpkgsBootstrap ? <nixpkgs>-, nixpkgs ? (import nixpkgsBootstrap {}).fetchFromGitHub {- owner = "NixOS";- repo = "nixpkgs-channels";- rev = "3eccd0b11d176489d69c778f2fcb544438f3ab56"; # unstable, dec 4 2017- sha256 = "1i3p5m0pnn86lzni5y1win0sacckw3wlg9kqaw15nszhykgz22zq"; }+{ nixpkgs ? builtins.fetchTarball channel:nixos-18.03 }: let pkgs = import nixpkgs {};--hsPackageSetConfig = self: super: {- flay = self.callPackage (import ./pkg.nix) {};-};--x = {- ghc802 = pkgs.haskell.packages.ghc802.override { packageSetConfig = hsPackageSetConfig; };- ghc822 = pkgs.haskell.packages.ghc822.override { packageSetConfig = hsPackageSetConfig; };+ghc841 = pkgs.haskell.packages.ghc841.override {+ packageSetConfig = self: super: {+ flay = super.callPackage ./pkg.nix {};+ }; }; -in rec {- ghc802 = { inherit (x.ghc802) flay; };- ghc822 = { inherit (x.ghc822) flay; };-- everything = pkgs.releaseTools.aggregate {- name = "everything";- meta.description = "Every job in release.nix";- constituents = [ ghc802.flay ghc822.flay ];- };-}+in { inherit (ghc841) flay; }
shell.nix view
@@ -1,2 +1,1 @@-{ compiler ? "ghc822" }:-(import ./release.nix {}).${compiler}.flay.env+(import ./default.nix).env
src/Flay.hs view
@@ -15,10 +15,10 @@ {-# LANGUAGE UndecidableSuperClasses #-} -- | The most commonly used names in this module are intended to be imported--- unqualified:+-- unqualified, as necessary: -- -- @--- import Flay (Flay, Flayable(flay), gflay, Dict(Dict))+-- import Flay (Flay, Flayable(flay), Flayable1(flay1)) -- @ -- -- The rest of the names, qualified:@@ -39,6 +39,7 @@ -- ** Utils , All , Trivial+ , trivialize , trivial , trivial1 , trivial'@@ -48,8 +49,6 @@ , zip , zip1 , unsafeZip- , Record- , GRecord , terminal , Terminal , GTerminal(gterminal)@@ -57,22 +56,18 @@ , Dict(Dict) ) where -import Control.Monad.ST (ST, runST)+import Control.Monad.Trans.Class (lift)+import Control.Monad.Trans.State (StateT(StateT), runStateT)+import Control.Monad.Trans.Maybe (MaybeT(MaybeT), runMaybeT)+import Data.Constraint (Constraint, Dict(Dict))+import Data.Dynamic (Dynamic, toDyn, fromDynamic)+import Data.Functor.Product (Product(Pair)) import Data.Functor.Const (Const(Const, getConst)) import Data.Functor.Identity (Identity(runIdentity))-import Data.Constraint (Constraint, Dict(Dict))-import Data.STRef (STRef, newSTRef, readSTRef, writeSTRef)+import Data.Typeable (Typeable) import qualified GHC.Generics as G import Prelude hiding (zip)-import Unsafe.Coerce (unsafeCoerce) -#if MIN_VERSION_ghc_prim(0,5,1)-import GHC.Types (Any)-#else-import GHC.Prim (Any)-#endif-- -------------------------------------------------------------------------------- -- | @'Flay' c s t f g@ allows converting @s@ to @t@ by replacing@@ -400,6 +395,13 @@ class Trivial (a :: k) instance Trivial (a :: k) +-- | Given a 'Flay' for any constraint @c@ obtain a 'Flay' for a 'Trivial'+-- constraint.+trivialize :: forall c s t f g. Flay c s t f g -> Flay Trivial s t f g+{-# INLINE trivialize #-}+trivialize fl0 = \h s ->+ fl0 (\(Dict :: Dict (c a)) (fa :: f a) -> h (Dict :: Dict (Trivial a)) fa) s+ -- | You can use 'trivial'' if you don't care about the @c@ argument to 'Flay'. -- This implies that you won't be able to observe the @a@ in @forall a. f a@, -- all you can do with such @a@ is pass it around.@@ -409,13 +411,13 @@ -- = fl (\\('Dict' :: 'Dict' ('Trivial' a)) (fa :: f a) -> h fa) -- @ trivial'- :: forall m s t f g+ :: forall m c s t f g . Applicative m- => Flay Trivial s t f g+ => Flay c s t f g -> (forall a. Trivial a => f a -> m (g a)) -> s -> m t -- ^-trivial' fl = \h -> \s -> fl (\Dict fa -> h fa) s+trivial' fl = \h -> \s -> trivialize fl (\Dict fa -> h fa) s {-# INLINE trivial' #-} -- | Like 'trivial'', but works on a 'Flayable' instead of taking an explicit@@ -425,11 +427,12 @@ -- 'trivial' = 'trivial'' 'flay' -- @ trivial- :: (Applicative m, Flayable Trivial s t f g)+ :: forall m s t f g+ . (Applicative m, Flayable Trivial s t f g) => (forall a. Trivial a => f a -> m (g a)) -> s -> m t -- ^-trivial = trivial' flay+trivial = trivial' (flay :: Flay Trivial s t f g) {-# INLINE trivial #-} -- | Like 'trivial'', but works on a 'Flayable1' instead of taking an explicit@@ -439,11 +442,12 @@ -- 'trivial' = 'trivial'' 'flay1' -- @ trivial1- :: (Applicative m, Flayable1 Trivial r)+ :: forall m f g r+ . (Applicative m, Flayable1 Trivial r) => (forall a. Trivial a => f a -> m (g a)) -> (r f) -> m (r g) -- ^-trivial1 = trivial' flay1+trivial1 = trivial' (flay1 :: Flay Trivial (r f) (r g) f g) {-# INLINE trivial1 #-} --------------------------------------------------------------------------------@@ -529,20 +533,6 @@ -------------------------------------------------------------------------------- --- | Handwavy class of which only product or record types are supposed to be--- instances.-class Record a-instance {-# OVERLAPPABLE #-} (G.Generic a, GRecord (G.Rep a)) => Record a--class GRecord (a :: * -> *) where-instance GRecord G.U1-instance GRecord (G.K1 r x)-instance GRecord x => GRecord (G.M1 i j x)-instance (GRecord l, GRecord r) => GRecord (l G.:*: r)------------------------------------------------------------------------------------ -- | Witness that @a@ is a terminal object. That is, that @a@ can always be -- constructed out of thin air. class Terminal a where@@ -594,57 +584,71 @@ -- Foo ('Const' \"(0,1)\") ('Const' \"False\") -- @ --+-- Returns 'Nothing' in case the indivual target types do not match.+-- -- Note: 'zip1' is safer but less general than 'unsafeZip'. zip1- :: (Record (s f), Flayable1 c s)- => (forall x. Dict (c x) -> f x -> g x -> h x)+ :: (Monad m, Typeable f, Flayable1 c s, Flayable1 Typeable s)+ => (forall x. Dict (c x) -> f x -> g x -> m (h x)) -> s f -> s g- -> s h -- ^-zip1 h = unsafeZip flay1 flay1 h+ -> m (Maybe (s h)) -- ^+zip1 h = unsafeZip flay1 flay1 flay1 h {-# INLINABLE zip1 #-} -- | Zip two 'Flayable's together. -- -- 'zip' is like 'zip1', but for 'Flayable's. --+-- Returns 'Nothing' in case the indivual target types do not match.+-- -- Note: 'zip' is safer but less general than 'unsafeZip'. zip- :: ( Record s0- , Flayable c s0 t0 f (Const ())- , Flayable c s1 t1 g h )- => (forall x. Dict (c x) -> f x -> g x -> h x)- -> s0+ :: ( Monad m, Typeable f+ , Flayable Typeable s1 t1 f (Const ())+ , Flayable Typeable s2 t2 g (Product f g)+ , Flayable c t2 t3 (Product f g) h )+ => (forall x. Dict (c x) -> f x -> g x -> m (h x)) -> s1- -> t1 -- ^-zip h = unsafeZip flay flay h+ -> s2+ -> m (Maybe t3) -- ^+zip h = unsafeZip flay flay flay h {-# INLINABLE zip #-} -- | Unsafe version of 'zip' that doesn't guarantee that the given 'Flay's--- target the same values. 'zip' makes this function safe by simply using--- 'flay' twice.+-- target the same values. 'zip' and 'zip1' make this function safe by simply+-- using 'flay' or 'flay1' three times.+--+-- Returns 'Nothing' in case the indivual target types do not match.++-- This implementation traverses the record three times. We could make it in+-- two, but that pollutes the constraints a bit. unsafeZip- :: forall c s0 s1 t0 t1 f g h- . Record s0- => (Flay c s0 t0 f (Const ()))- -> (Flay c s1 t1 g h)- -> (forall x. Dict (c x) -> f x -> g x -> h x)- -> s0+ :: forall c s1 s2 t1 t2 t3 f g h m+ . (Monad m, Typeable f)+ => (Flay Typeable s1 t1 f (Const ()))+ -> (Flay Typeable s2 t2 g (Product f g))+ -> (Flay c t2 t3 (Product f g) h)+ -> (forall x. Dict (c x) -> f x -> g x -> m (h x)) -> s1- -> t1 -- ^-unsafeZip fl0 fl1 pair = \s0 s1 -> runST $ do- r <- newSTRef (collect' fl0 f1 s0)- fl1 (f2 r) s1- where- f1 :: Dict (c a) -> f a -> [Any]- f1 = \Dict fa -> [unsafeCoerce fa :: Any]- f2 :: STRef z [Any] -> Dict (c a) -> g a -> ST z (h a)- f2 r = \Dict !ga -> do- (x:xs) <- readSTRef r- writeSTRef r xs- let !fa = unsafeCoerce (x :: Any) :: f a- pure $! pair Dict fa ga+ -> s2+ -> m (Maybe t3) -- ^+unsafeZip fl1 fl2 fl3 pair = \s1 s2 -> runMaybeT $ do+ (t2, dyns) <- runStateT (fl2 f2 s2) (collect' fl1 f1 s1)+ case dyns of+ [] -> lift (fl3 f3 t2)+ _ -> MaybeT (pure Nothing)+ where+ f1 :: Dict (Typeable a) -> f a -> [Dynamic]+ f1 = \Dict !fa -> [toDyn fa :: Dynamic]+ f2 :: Dict (Typeable a) -> g a -> StateT [Dynamic] (MaybeT m) (Product f g a)+ f2 = \Dict !ga -> StateT $ \(x:xs) -> do+ !(fa :: f a) <- MaybeT (pure (fromDynamic x))+ pure (Pair fa ga, xs)+ f3 :: Dict (c a) -> Product f g a -> m (h a)+ f3 = \Dict (Pair fa ga) -> pair Dict fa ga + -------------------------------------------------------------------------------- -- | Ensure that @x@ satisfies all of the constraints listed in @cs@.@@ -657,3 +661,4 @@ type family All' (cs :: [k -> Constraint]) (x :: k) :: Constraint where All' (c ': cs) x = (c x, All' cs x) All' '[] _ = ()+