type-level-kv-list 1.1.0 → 2.0.0
raw patch · 7 files changed
+324/−188 lines, 7 filesdep ~basePVP ok
version bump matches the API change (PVP)
Dependency ranges changed: base
API changes (from Hackage documentation)
- Data.TypeLevelKVList: (:.) :: a -> b -> (:.) a b
- Data.TypeLevelKVList: Null :: Null
- Data.TypeLevelKVList: class NamedList layout
- Data.TypeLevelKVList: data (:.) a b
- Data.TypeLevelKVList: data Null
- Data.TypeLevelKVList: get :: (HasKey list pkey (Lookup pkey list)) => pkey -> list -> Lookup pkey list
- Data.TypeLevelKVList: instance (Data.TypeLevelKVList.NamedList b, GHC.TypeLits.KnownSymbol k) => Data.TypeLevelKVList.NamedList (Data.TypeLevelKVList.NamedVal v k Data.TypeLevelKVList.:. b)
- Data.TypeLevelKVList: instance (GHC.Classes.Eq b, GHC.Classes.Eq a) => GHC.Classes.Eq (a Data.TypeLevelKVList.:. b)
- Data.TypeLevelKVList: instance (GHC.Show.Show b, GHC.Show.Show a) => GHC.Show.Show (a Data.TypeLevelKVList.:. b)
- Data.TypeLevelKVList: instance Data.TypeLevelKVList.NamedList Data.TypeLevelKVList.Null
- Data.TypeLevelKVList: instance GHC.Classes.Eq Data.TypeLevelKVList.Null
- Data.TypeLevelKVList: instance GHC.Show.Show Data.TypeLevelKVList.Null
- Data.TypeLevelKVList: instance forall k (k1 :: k). Data.TypeLevelKVList.HasKey Data.TypeLevelKVList.Null (Data.Proxy.Proxy k1) Data.TypeLevelKVList.Null
- Data.TypeLevelKVList: instance forall k b (k1 :: k) v a. Data.TypeLevelKVList.HasKey b (Data.Proxy.Proxy k1) v => Data.TypeLevelKVList.HasKey (a Data.TypeLevelKVList.:. b) (Data.Proxy.Proxy k1) v
- Data.TypeLevelKVList: instance forall k v (k1 :: k) b. Data.TypeLevelKVList.HasKey (Data.TypeLevelKVList.NamedVal v k1 Data.TypeLevelKVList.:. b) (Data.Proxy.Proxy k1) v
- Data.TypeLevelKVList: keys :: NamedList layout => Proxy layout -> [String]
- Data.TypeLevelKVList: keys' :: NamedList k => k -> [String]
- Data.TypeLevelKVList: namedVal :: v -> NamedVal v k
- Data.TypeLevelKVList: type NamedVal v key = (Proxy key, v)
+ Data.KVList: (&.) :: (KnownSymbol key, HasKey key kvs v) => KVList kvs -> ListKey key -> v
+ Data.KVList: (&=) :: (KnownSymbol k, Appended kvs '[k := v] ~ appended) => KVList kvs -> (k := v) -> KVList appended
+ Data.KVList: ListKey :: ListKey (t :: Symbol)
+ Data.KVList: [:=] :: ListKey a -> b -> a := b
+ Data.KVList: data (key :: Symbol) := (value :: Type)
+ Data.KVList: data KVList (kvs :: [Type])
+ Data.KVList: data ListKey (t :: Symbol)
+ Data.KVList: empty :: KVList '[]
+ Data.KVList: get :: (KnownSymbol key, HasKey key kvs v) => ListKey key -> KVList kvs -> v
+ Data.KVList: infix 2 :=
+ Data.KVList: infixl 1 &=
+ Data.KVList: infixl 9 &.
+ Data.KVList: instance (l GHC.Types.~ l') => GHC.OverloadedLabels.IsLabel l (Data.KVList.ListKey l')
+ Data.KVList: instance GHC.Classes.Eq (Data.KVList.ListKey t)
+ Data.KVList: instance GHC.Show.Show (Data.KVList.ListKey t)
+ Data.KVList: instance GHC.Show.Show value => GHC.Show.Show (key Data.KVList.:= value)
+ Data.KVList: kvcons :: KnownSymbol k => (k := v) -> KVList kvs -> KVList ((k := v) : kvs)
+ Data.KVList: singleton :: KnownSymbol k => (k := v) -> KVList '[k := v]
+ Data.KVList: type HasKey (key :: Symbol) (kvs :: [Type]) (v :: Type) = HasKey_ key kvs kvs v
Files
- README.md +9/−0
- src/Data/KVList.hs +133/−0
- src/Data/TypeLevelKVList.hs +0/−130
- test/DocTest.hs +57/−0
- test/Doctest.hs +0/−17
- test/Spec.hs +0/−2
- type-level-kv-list.cabal +125/−39
+ README.md view
@@ -0,0 +1,9 @@+[](https://github.com/arowM/type-level-kv-list/actions/workflows/test.yaml)+[](https://hackage.haskell.org/package/type-level-kv-list)+[](http://stackage.org/lts/package/type-level-kv-list)+[](http://stackage.org/nightly/package/type-level-kv-list)++# type-level-kv-list++This library provides a brief implementation for extensible records.+It is sensitive to the ordering of key-value items, but has simple type constraints and provides short compile time.
+ src/Data/KVList.hs view
@@ -0,0 +1,133 @@+{-| This library provide a brief implementation for extensible records.+ It is sensitive to the ordering of key-value items, but has simple type constraints and provides short compile time.+-}++{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE UndecidableInstances #-}++module Data.KVList+ (+ -- * Constructors+ -- $setup+ KVList+ , (:=)((:=))+ , (&=)+ , kvcons+ , empty+ , singleton+ , ListKey(..)++ -- * Operators+ , get+ , HasKey+ , (&.)+ )+where++import Prelude++import Data.Kind (Constraint, Type)+import Data.Typeable (Typeable, typeOf)+import GHC.TypeLits (KnownSymbol, Symbol, TypeError, ErrorMessage(Text))+import GHC.OverloadedLabels (IsLabel(..))+import Unsafe.Coerce (unsafeCoerce)+++-- Constructors++{- $setup #constructors#+ We can create type level KV list as follows.++ >>> :set -XOverloadedLabels -XTypeOperators+ >>> import Prelude+ >>> import Data.KVList (empty, KVList, (:=)((:=)), (&.), (&=))+ >>> let sampleList = empty &= #foo := "str" &= #bar := 34+ >>> type SampleList = KVList '[ "foo" := String, "bar" := Int ]+-}++{-| A value with type level key.+-}+data KVList (kvs :: [Type]) where+ KVNil :: KVList '[]+ KVCons :: (KnownSymbol key) => key := v -> KVList xs -> KVList ((key := v) ': xs)++{-| -}+empty :: KVList '[]+empty = KVNil++(&=) :: (KnownSymbol k, Appended kvs '[k := v] ~ appended) => KVList kvs -> (k := v) -> KVList appended+(&=) kvs kv = append kvs (singleton kv)+{-# INLINE (&=) #-}++infixl 1 &=++{-| -}+kvcons :: (KnownSymbol k) => (k := v) -> KVList kvs -> KVList ((k := v) ': kvs)+kvcons = KVCons++{-| -}+data (key :: Symbol) := (value :: Type) where+ (:=) :: ListKey a -> b -> a := b+infix 2 :=++deriving instance (Show value) => Show (key := value)++{-| -}+type HasKey (key :: Symbol) (kvs :: [Type]) (v :: Type) = HasKey_ key kvs kvs v++type family HasKey_ (key :: Symbol) (kvs :: [Type]) (orig :: [Type]) (v :: Type) :: Constraint where+ HasKey_ key '[] '[] v = TypeError ('Text "The KVList is empty.")+ HasKey_ key '[] orig v = TypeError ('Text "The Key is not in the KVList.")+ HasKey_ key ((key := val) ': _) _ v = (val ~ v)+ HasKey_ key (_ ': kvs) orig v = HasKey_ key kvs orig v++{-| -}+type family Appended kvs1 kv2 :: [Type] where+ Appended '[] kv2 = kv2+ Appended (kv ': kvs) kv2 =+ kv ': Appended kvs kv2++{-| -}+append :: (Appended kvs1 kvs2 ~ appended) => KVList kvs1 -> KVList kvs2 -> KVList appended+append KVNil kvs2 = kvs2+append (KVCons kv kvs) kvs2 = KVCons kv (append kvs kvs2)+++{-| -}+singleton :: (KnownSymbol k) => (k := v) -> KVList '[ k := v ]+singleton kv = KVCons kv KVNil+++{-| -}+get :: (KnownSymbol key, HasKey key kvs v) => ListKey key -> KVList kvs -> v+get p kvs = get_ p kvs kvs++get_ :: (KnownSymbol key, HasKey key orig v) => ListKey key -> KVList kvs -> KVList orig -> v+get_ _ KVNil KVNil = error "Unreachable: The KVList is empty."+get_ _ KVNil _ = error "Unreachable: The Key is not in the KVList."+get_ p (KVCons (k := v) kvs) orig =+ if typeOf p == typeOf k then+ unsafeCoerce v+ else+ get_ p kvs orig+++{-| -}+(&.) :: (KnownSymbol key, HasKey key kvs v) => KVList kvs -> ListKey key -> v+(&.) kvs k = get k kvs+infixl 9 &.++{-| 'ListKey' is just a proxy, but needed to implement a non-orphan 'IsLabel' instance.+In most cases, you only need to create a `ListKey` instance with @OverloadedLabels@, such as `#foo`.+-}+data ListKey (t :: Symbol)+ = ListKey+ deriving (Show, Eq, Typeable)++instance l ~ l' => IsLabel (l :: Symbol) (ListKey l') where+#if MIN_VERSION_base(4, 10, 0)+ fromLabel = ListKey+#else+ fromLabel _ = ListKey+#endif
− src/Data/TypeLevelKVList.hs
@@ -1,130 +0,0 @@-{-|- This module supply a way to construct type safe key-value pair list- and convenient operations for the type.--}--{-# LANGUAGE DataKinds #-}-{-# LANGUAGE TypeOperators #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE TypeInType #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE IncoherentInstances #-}--module Data.TypeLevelKVList- (- -- * Constructors- -- $setup- NamedVal- , namedVal- , (:.)(..)- , Null(..)-- -- * Operators- , get- , Lookup- , keys- , keys'-- -- * Misc- , NamedList- )-where--import Data.Proxy (Proxy(..))-import Data.Typeable (Typeable)-import GHC.TypeLits (KnownSymbol, symbolVal)---- Constructors--{- $setup #constructors#- We can create type level KV list as follows.-- >>> :set -XDataKinds -XTypeOperators- >>> let sampleList = (namedVal "str" :: NamedVal String "foo") :. (namedVal 34 :: NamedVal Int "bar") :. Null- >>> type SampleList = NamedVal String "foo" :. NamedVal Int "bar" :. Null--}--{-| A value with type level key.- -}-type NamedVal v key = (Proxy key, v)--{-| A convenient function to construct type level KV list.- -}-namedVal :: v -> NamedVal v k-namedVal a = (Proxy, a)--{-| Type level list cons.- -}-data a :. b = a :. b- deriving (Typeable, Eq, Show)-infixr 8 :.--{-| Type level empty list.- -}-data Null = Null- deriving (Typeable, Eq, Show)--{-| Type level @lookup :: k -> [(k, a)] -> a@.- -}-type family Lookup pkey list where- Lookup pk ((pk, v) :. b) = v- Lookup pk ((px, v) :. b) = Lookup pk b- Lookup pk Null = Null--{-| Main class for a list of values with type level key- -}-class NamedList layout where- type family NamedList' layout- {-|- >>> keys (Proxy :: Proxy SampleList)- ["foo","bar"]- -}- keys :: Proxy layout -> [String]--instance (NamedList b, KnownSymbol k) => NamedList (NamedVal v k :. b) where- type NamedList' (NamedVal v k :. b) = NamedVal v k :. NamedList' b- keys _ = symbolVal (Proxy :: Proxy k) : keys (Proxy :: Proxy b)--instance NamedList Null where- type NamedList' Null = Null- keys _ = []--{-| Chek if the key is included in type level list.- -}-class HasKey list pkey value where- get' :: pkey -> list -> value--instance HasKey (NamedVal v k :. b) (Proxy k) v where- get' _ ((_, a) :. _) = a--instance HasKey b (Proxy k) v =>- HasKey (a :. b) (Proxy k) v where- get' p (_ :. b) = get' p b--instance HasKey Null (Proxy k) Null where- get' _ Null = Null--{-|- >>> get (Proxy :: Proxy "foo") sampleList- "str"-- >>> get (Proxy :: Proxy "bar") sampleList- 34-- >>> get (Proxy :: Proxy "baz") sampleList- Null--}-get :: (HasKey list pkey (Lookup pkey list))- => pkey -> list -> Lookup pkey list-get (pkey :: pkey) (list :: list) =- get' pkey list :: Lookup pkey list--{-|- >>> keys' sampleList- ["foo","bar"]--}-keys' :: NamedList k => k -> [String]-keys' (_ :: k) = keys (Proxy :: Proxy k)
+ test/DocTest.hs view
@@ -0,0 +1,57 @@+module Main (main) where++import Prelude++import System.FilePath.Glob (glob)+import Test.DocTest (doctest)++main :: IO ()+main = glob "src/**/*.hs" >>= doDocTest++doDocTest :: [String] -> IO ()+doDocTest options =+ doctest $+ options <>+ ghcExtensions++ghcExtensions :: [String]+ghcExtensions =+ [ "-XBangPatterns"+ , "-XBinaryLiterals"+ , "-XConstraintKinds"+ , "-XDataKinds"+ , "-XDefaultSignatures"+ , "-XDeriveDataTypeable"+ , "-XDeriveFoldable"+ , "-XDeriveFunctor"+ , "-XDeriveGeneric"+ , "-XDeriveTraversable"+ , "-XDoAndIfThenElse"+ , "-XDuplicateRecordFields"+ , "-XEmptyDataDecls"+ , "-XExistentialQuantification"+ , "-XFlexibleContexts"+ , "-XFlexibleInstances"+ , "-XFunctionalDependencies"+ , "-XGADTs"+ , "-XGeneralizedNewtypeDeriving"+ , "-XInstanceSigs"+ , "-XKindSignatures"+ , "-XLambdaCase"+ , "-XMultiParamTypeClasses"+ , "-XMultiWayIf"+ , "-XNamedFieldPuns"+ , "-XNoImplicitPrelude"+ , "-XOverloadedStrings"+ , "-XPartialTypeSignatures"+ , "-XPatternGuards"+ , "-XPolyKinds"+ , "-XRankNTypes"+ , "-XRecordWildCards"+ , "-XScopedTypeVariables"+ , "-XStandaloneDeriving"+ , "-XTupleSections"+ , "-XTypeFamilies"+ , "-XTypeSynonymInstances"+ , "-XViewPatterns"+ ]
− test/Doctest.hs
@@ -1,17 +0,0 @@-module Main where--import Data.Monoid ((<>))-import System.FilePath.Glob (glob)-import Test.DocTest (doctest)--main :: IO ()-main = glob "src/**/*.hs" >>= doDocTest--doDocTest :: [String] -> IO ()-doDocTest options = doctest $ options <> ghcExtensions--ghcExtensions :: [String]-ghcExtensions =- [ "-XDataKinds"- , "-XTypeOperators"- ]
− test/Spec.hs
@@ -1,2 +0,0 @@-main :: IO ()-main = putStrLn "Test suite not yet implemented"
type-level-kv-list.cabal view
@@ -1,44 +1,130 @@-name: type-level-kv-list-version: 1.1.0-synopsis: A module for hash map like object with type level keys.-description: Please see README.md-homepage: https://github.com/arowM/type-level-kv-list#readme-license: MIT-license-file: LICENSE-author: Kadzuya Okamoto-maintainer: arow.okamoto+github@gmail.com-copyright: 2016 Kadzuya Okamoto-category: Data-build-type: Simple--- extra-source-files:-cabal-version: >=1.10--library- hs-source-dirs: src- exposed-modules: Data.TypeLevelKVList- build-depends: base >= 4.7 && < 5- default-language: Haskell2010+cabal-version: 1.12 -test-suite type-level-kv-list-test- type: exitcode-stdio-1.0- hs-source-dirs: test- main-is: Spec.hs- build-depends: base- , type-level-kv-list- ghc-options: -threaded -rtsopts -with-rtsopts=-N- default-language: Haskell2010+-- This file has been generated from package.yaml by hpack version 0.34.4.+--+-- see: https://github.com/sol/hpack -test-suite doctest- type: exitcode-stdio-1.0- hs-source-dirs: test- main-is: Doctest.hs- build-depends: base- , Glob- , doctest- , type-level-kv-list- ghc-options: -threaded -rtsopts -with-rtsopts=-N- default-language: Haskell2010+name: type-level-kv-list+version: 2.0.0+synopsis: Type level Key-Value list.+description: This library provides a brief implementation for extensible records.+category: Data+homepage: https://github.com/arowM/type-level-kv-list#readme+bug-reports: https://github.com/arowM/type-level-kv-list/issues+author: Sakura-chan the Goat+maintainer: arow.okamoto+github@gmail.com+copyright: 2016 Sakura-chan the Goat+license: MIT+license-file: LICENSE+build-type: Simple+extra-source-files:+ README.md source-repository head- type: git+ type: git location: https://github.com/arowM/type-level-kv-list++library+ exposed-modules:+ Data.KVList+ other-modules:+ Paths_type_level_kv_list+ hs-source-dirs:+ src+ default-extensions:+ BangPatterns+ BinaryLiterals+ ConstraintKinds+ DataKinds+ DefaultSignatures+ DeriveDataTypeable+ DeriveFoldable+ DeriveFunctor+ DeriveGeneric+ DeriveTraversable+ DoAndIfThenElse+ DuplicateRecordFields+ EmptyDataDecls+ ExistentialQuantification+ FlexibleContexts+ FlexibleInstances+ FunctionalDependencies+ GADTs+ GeneralizedNewtypeDeriving+ InstanceSigs+ KindSignatures+ LambdaCase+ MultiParamTypeClasses+ MultiWayIf+ NamedFieldPuns+ OverloadedStrings+ PartialTypeSignatures+ PatternGuards+ PolyKinds+ RankNTypes+ RecordWildCards+ ScopedTypeVariables+ StandaloneDeriving+ Strict+ StrictData+ TupleSections+ TypeFamilies+ TypeSynonymInstances+ ViewPatterns+ ghc-options: -Wall -Wcompat -Wincomplete-record-updates -Wincomplete-uni-patterns -Wredundant-constraints+ build-depends:+ base >=4.7 && <5+ default-language: Haskell2010++test-suite doctest+ type: exitcode-stdio-1.0+ main-is: DocTest.hs+ hs-source-dirs:+ test+ default-extensions:+ BangPatterns+ BinaryLiterals+ ConstraintKinds+ DataKinds+ DefaultSignatures+ DeriveDataTypeable+ DeriveFoldable+ DeriveFunctor+ DeriveGeneric+ DeriveTraversable+ DoAndIfThenElse+ DuplicateRecordFields+ EmptyDataDecls+ ExistentialQuantification+ FlexibleContexts+ FlexibleInstances+ FunctionalDependencies+ GADTs+ GeneralizedNewtypeDeriving+ InstanceSigs+ KindSignatures+ LambdaCase+ MultiParamTypeClasses+ MultiWayIf+ NamedFieldPuns+ OverloadedStrings+ PartialTypeSignatures+ PatternGuards+ PolyKinds+ RankNTypes+ RecordWildCards+ ScopedTypeVariables+ StandaloneDeriving+ Strict+ StrictData+ TupleSections+ TypeFamilies+ TypeSynonymInstances+ ViewPatterns+ ghc-options: -Wall -Wcompat -Wincomplete-record-updates -Wincomplete-uni-patterns -Wredundant-constraints+ build-depends:+ Glob+ , base >=4.7 && <5+ , doctest+ , type-level-kv-list+ default-language: Haskell2010