packages feed

fcf-family 0.1.0.0 → 0.2.0.0

raw patch · 5 files changed

+60/−12 lines, 5 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Fcf.Family.TH: fcfify' :: Name -> Q [Dec]
+ Fcf.Family.TH: fcfifySkip :: Name -> Q [Dec]

Files

CHANGELOG.md view
@@ -1,5 +1,13 @@ # Revision history for fcf-family +[Current version](https://gitlab.com/lysxia/fcf-family/-/blob/main/fcf-family/CHANGELOG.md)++## 0.2.0.0++- Change `fcfify` to deduplicate calls with the same argument.+- Add `fcfify'` with the old stateless behavior.+- Add `fcfifySkip`.+ ## 0.1.0.0 -- 2023-01-23  * First version. Released on an unsuspecting world.
fcf-family.cabal view
@@ -1,6 +1,6 @@ cabal-version:      3.0 name:               fcf-family-version:            0.1.0.0+version:            0.2.0.0 synopsis: Family of families: featherweight defunctionalization description:   Promote regular type families to first-class,
src/Fcf/Family.hs view
@@ -15,13 +15,12 @@ -- = The family of type families -- -- /fcf-family/ promotes--- regular type families to first-class families without--- defining new symbols (which would either pollute the type namespace--- or require a centralized organization to decide where the symbol--- for each family should be defined).+-- regular type families to first-class families without requiring new symbols+-- that pollute the type namespace nor a centralized organization to decide+-- where the symbol for each family should be defined. ----- Every type family is uniquely identified by its qualified 'Name':--- package, module, and base name.+-- All we need is a single symbol 'Family' indexed by a qualified name that+-- uniquely identifies an existing type family: package, module, and base name. -- -- Example names: --@@ -32,9 +31,6 @@ -- -- Data.Type.Bool.If -- 'MkName' \"base\" \"Data.Type.Bool\" \"If\" -- @------ Hence, a single symbol 'Family' indexed by names--- is sufficient to promote all regular type families. -- -- == Promoting a type family to first-class --
src/Fcf/Family/Meta.hs view
@@ -1,5 +1,4 @@ {-# LANGUAGE DataKinds, PolyKinds, TemplateHaskell, TypeFamilies #-}--- {-# OPTIONS_GHC -ddump-splices #-}  -- | 'Eval' and friends as part of the family of families. module Fcf.Family.Meta () where
src/Fcf/Family/TH.hs view
@@ -8,6 +8,8 @@ module Fcf.Family.TH   ( -- * Generate boilerplate     fcfify+  , fcfifySkip+  , fcfify'      -- * Using promoted families   , promoteFamily@@ -24,22 +26,65 @@   ) where  import Control.Applicative (liftA2)+import Control.Monad (when) import Data.Function (on)+import Data.Functor (($>)) import Data.List (sort) import Data.Maybe (fromMaybe) import Data.Foldable (foldl') import Data.Traversable (for)+import Data.Set (Set) import qualified Data.Set as Set import Language.Haskell.TH+import Language.Haskell.TH.Syntax (getQ, putQ)  import Fcf.Core import Fcf.Family hiding (Name)  -- | Generate the boilerplate needed to promote a type family to first class. --+-- Required extensions:+--+-- - @DataKinds@+-- - @PolyKinds@+-- - @TypeFamilies@+--+-- If 'fcfify' is called more than once with the same 'Name' in the same module,+-- only the first invocation generates declarations; subsequent declarations+-- return the empty list, avoiding duplicate declarations in the current module.+--+-- For a stateless variant, use 'fcfify''.+-- -- See "Fcf.Family" for details on the encoding. fcfify :: Name -> Q [Dec]-fcfify name = reifyTyInfo name >>= fcfifyInfo+fcfify name = do+  check <- checkFcfified name+  if check then pure [] else fcfify' name++-- | Mark a type family as already fcifified.+fcfifySkip :: Name -> Q [Dec]+fcfifySkip name = checkFcfified name $> []++-- | Store invocations of 'fcfify' to avoid generating duplicate instances+-- in the current module (a minor performance optimization).+newtype Fcfified = Fcfified (Set Name)++-- | Check whether we've already seen this name.+-- Add the name to the registered set.+checkFcfified :: Name -> Q Bool+checkFcfified name = do+  Fcfified seen <- fromMaybe (Fcfified Set.empty) <$> getQ+  let check = name `Set.member` seen+  when (not check) (putQ (Fcfified (Set.insert name seen)))+  pure check+++-- | Generate the boilerplate needed to promote a type family to first class.+--+-- Unlike 'fcfify', this always returns the same declarations for the same+-- named type.+fcfify' :: Name -> Q [Dec]+fcfify' name = reifyTyInfo name >>= fcfifyInfo   where     ?funName = "fcfify"     ?name = name