first-class-families 0.3.0.1 → 0.4.0.0
raw patch · 5 files changed
+134/−5 lines, 5 filesdep +first-class-familiesdep ~basePVP ok
version bump matches the API change (PVP)
Dependencies added: first-class-families
Dependency ranges changed: base
API changes (from Hackage documentation)
+ Fcf: (:=) :: a -> b -> Guard a b
+ Fcf: data Guard a b
+ Fcf: data Guarded :: a -> [Guard (a -> Exp Bool) (Exp b)] -> Exp b
+ Fcf: data LiftM2 :: (a -> b -> Exp c) -> Exp a -> Exp b -> Exp c
+ Fcf: data LiftM3 :: (a -> b -> c -> Exp d) -> Exp a -> Exp b -> Exp c -> Exp d
+ Fcf: infixl 4 <*>
+ Fcf: infixr 0 $
+ Fcf: infixr 1 <=<
+ Fcf: infixr 2 ||
+ Fcf: infixr 3 &&
+ Fcf: type LiftM = (=<<)
+ Fcf: type Otherwise = ConstFn 'True
+ Fcf: type family If (b :: Bool) (x :: k) (y :: k) :: k
- Fcf: _If :: IsBool b => ((b ~ 'True) => r) -> ((b ~ 'False) => r) -> r
+ Fcf: _If :: IsBool b => (b ~ 'True => r) -> (b ~ 'False => r) -> r
Files
- CHANGELOG.md +10/−2
- README.md +39/−2
- first-class-families.cabal +10/−1
- src/Fcf.hs +47/−0
- test/test.hs +28/−0
CHANGELOG.md view
@@ -1,14 +1,22 @@+# 0.4.0.0++- New functions (blmage)++ + `LiftM`, `LiftM2`, `LiftM3`+ + `(<=)`, `(>=)`, `(<)`, `(>)`+ + `Guarded`, `Guard((:=))`, `Otherwise`+ # 0.3.0.1 - GHC 8.6 compatibility # 0.3.0.0 -- More new functions, thanks to isovector+- More new functions, (isovector) # 0.2.0.0 -- A whole bunch of basic functions, thanks to isovector+- A whole bunch of basic functions (isovector) - Remove `Traverse` (now `Map`), `BimapPair`, `BimapEither` (now `Bimap`) # 0.1.0.0
README.md view
@@ -1,8 +1,45 @@ # First-class type families [](https://hackage.haskell.org/package/first-class-families) [](https://travis-ci.org/Lysxia/first-class-families) -[Haskell with only one type family](http://blog.poisson.chat/posts/2018-08-06-one-type-family.html) (blogpost)+For example, consider this simple type family: -See `src/Fcf`.+```haskell+type family FromMaybe (a :: k) (m :: Maybe k) :: k+type instance FromMaybe a 'Nothing = a+type instance FromMaybe a ('Just b) = b+```++With first-class-families, it translates to a `data` declaration+and instances for a single `Eval` family:++```haskell+import Fcf++data FromMaybe :: k -> Maybe k -> Exp k+type instance Eval (FromMaybe a 'Nothing) = a+type instance Eval (FromMaybe a ('Just b)) = b+```++That way, the `FromMaybe` constructor can be passed to higher-order fcfs.++```haskell+Eval (Map (FromMaybe 0) '[ 'Just 1, 'Nothing ]) = '[ 1, 0 ] :: [Nat]+```++Essential language extensions:++```haskell+{-# LANGUAGE+ DataKinds,+ PolyKinds,+ TypeFamilies,+ TypeInType,+ TypeOperators,+ UndecidableInstances #-}+```++## See also++[Haskell with only one type family](http://blog.poisson.chat/posts/2018-08-06-one-type-family.html) (blogpost) ---
first-class-families.cabal view
@@ -1,5 +1,5 @@ name: first-class-families-version: 0.3.0.1+version: 0.4.0.0 synopsis: First class type families description:@@ -28,6 +28,15 @@ base >= 4.9 && < 5 ghc-options: -Wall default-language: Haskell2010++test-suite fcf-test+ type: exitcode-stdio-1.0+ hs-source-dirs: test+ main-is: test.hs+ default-language: Haskell2010+ build-depends:+ base,+ first-class-families source-repository head type: git
src/Fcf.hs view
@@ -76,6 +76,14 @@ data (<=<) :: (b -> Exp c) -> (a -> Exp b) -> a -> Exp c type instance Eval ((f <=< g) x) = Eval (f (Eval (g x))) +type LiftM = (=<<)++data LiftM2 :: (a -> b -> Exp c) -> Exp a -> Exp b -> Exp c+type instance Eval (LiftM2 f x y) = Eval (f (Eval x) (Eval y))++data LiftM3 :: (a -> b -> c -> Exp d) -> Exp a -> Exp b -> Exp c -> Exp d+type instance Eval (LiftM3 f x y z) = Eval (f (Eval x) (Eval y) (Eval z))+ data Join :: Exp (Exp a) -> Exp a type instance Eval (Join e) = Eval (Eval e) @@ -294,6 +302,33 @@ type instance Eval (Not 'True) = 'False type instance Eval (Not 'False) = 'True +-- | A conditional choosing the first branch whose guard @a -> 'Exp' 'Bool'@+-- accepts a given value @a@.+--+-- === Example+--+-- @+-- type UnitPrefix n = 'Eval' ('Guarded' n+-- '[ 'TyEq' 0 \'':=' 'Pure' \"\"+-- , 'TyEq' 1 \'':=' 'Pure' \"deci\"+-- , 'TyEq' 2 \'':=' 'Pure' \"hecto\"+-- , 'TyEq' 3 \'':=' 'Pure' \"kilo\"+-- , 'TyEq' 6 \'':=' 'Pure' \"mega\"+-- , 'TyEq' 9 \'':=' 'Pure' \"giga\"+-- , 'Otherwise' \'':=' 'Error' "Something else"+-- ])+-- @+data Guarded :: a -> [Guard (a -> Exp Bool) (Exp b)] -> Exp b+type instance Eval (Guarded x ((p ':= y) ': ys)) =+ Eval (If (Eval (p x)) y (Guarded x ys))++-- | A fancy-looking pair type to use with 'Guarded'.+data Guard a b = a := b+infixr 0 :=++-- | A catch-all guard for 'Guarded'.+type Otherwise = ConstFn 'True+ -- ** Nat data (+) :: Nat -> Nat -> Exp Nat@@ -307,6 +342,18 @@ data (^) :: Nat -> Nat -> Exp Nat type instance Eval ((^) a b) = a TL.^ b++data (<=) :: Nat -> Nat -> Exp Bool+type instance Eval ((<=) a b) = a TL.<=? b++data (>=) :: Nat -> Nat -> Exp Bool+type instance Eval ((>=) a b) = b TL.<=? a++data (<) :: Nat -> Nat -> Exp Bool+type instance Eval ((<) a b) = Eval (Not =<< (a >= b))++data (>) :: Nat -> Nat -> Exp Bool+type instance Eval ((>) a b) = Eval (Not =<< (a <= b)) -- ** Other
+ test/test.hs view
@@ -0,0 +1,28 @@+{-# LANGUAGE+ DataKinds,+ KindSignatures,+ TypeOperators #-}++import Data.Type.Equality ((:~:)(Refl))+import GHC.TypeLits (Nat)+import Fcf++type UnitPrefix (n :: Nat) = Eval (Guarded n+ '[ TyEq 0 ':= Pure ""+ , TyEq 1 ':= Pure "deci"+ , TyEq 2 ':= Pure "hecto"+ , TyEq 3 ':= Pure "kilo"+ , TyEq 6 ':= Pure "mega"+ , TyEq 9 ':= Pure "giga"+ , Otherwise ':= Error "Something else"+ ])++-- Compile-time tests++_ = Refl :: UnitPrefix 0 :~: ""+_ = Refl :: UnitPrefix 9 :~: "giga"++-- Dummy++main :: IO ()+main = pure ()