enumerate 0.1.0 → 0.1.1
raw patch · 5 files changed
+164/−35 lines, 5 filesdep +arraydep ~enumeratenew-component:exe:enumerate-example
Dependencies added: array
Dependency ranges changed: enumerate
Files
- README.md +1/−1
- enumerate.cabal +5/−4
- sources/Data/Enumerate.hs +13/−9
- sources/Data/Enumerate/Enum.hs +94/−0
- sources/Data/Enumerate/Example.hs +51/−21
README.md view
@@ -9,7 +9,7 @@ ```haskell {-# LANGUAGE DeriveGeneric, DeriveAnyClass #-} - import Data.Enumerable (Enumerable(..)) + import Data.Enumerate (Enumerable(..)) import Data.Generics (Generics) data CrudOp = Add | Edit | Delete | View
enumerate.cabal view
@@ -2,7 +2,7 @@ -- documentation, see http://haskell.org/cabal/users-guide/ name: enumerate -version: 0.1.0 +version: 0.1.1 synopsis: enumerate all the values in a finite type (automatically) description: provides (1) a typeclass for enumerating all values in a finite type, (2) a generic instance for automatic deriving, and (3) helpers that reify functions (partial or total, monadic or pure) into a Map. @@ -17,7 +17,6 @@ extra-source-files: README.md cabal-version: >=1.10 - library exposed-modules: Data.Enumerate @@ -29,6 +28,7 @@ Data.Enumerate.Extra Data.Enumerate.Large Data.Enumerate.Function + Data.Enumerate.Enum -- Data.CoRec -- Data.CoRec.MemoTrie -- Data.TEnumerate @@ -37,6 +37,7 @@ base ==4.8.* , containers ==0.5.* , ghc-prim==0.4.* + , array ==0.5.* , semigroups ==0.18.* , exceptions ==0.8.* @@ -52,7 +53,7 @@ default-language: Haskell2010 -executable example +executable enumerate-example main-is: Main.hs hs-source-dirs: . @@ -60,4 +61,4 @@ build-depends: base >=4.8 && <4.9 - , enumerate ==0.0.0 + , enumerate
sources/Data/Enumerate.hs view
@@ -1,23 +1,27 @@-{-| see "Data.Enumerable.Types" for detailed documentation. +{-| see "Data.Enumerable.Types" for detailed documentation. to import every symbol in this package, run this in GHCi: @ -:m + Data.Enumerate Data.Enumerate.Extra Data.Enumerate.Large Data.Enumerate.Function +:m + Data.Enumerate Data.Enumerate.Extra Data.Enumerate.Large Data.Enumerate.Function @ -the modules "Data.Enumerate.Large" and "Data.Enumerate.Function" have orphan instances for large types, -and aren't reexported by default. -this makes attempting to enumerate them a type error, rather than runtime non-termination. +the modules "Data.Enumerate.Large" and "Data.Enumerate.Function" have orphan instances for large types, +and aren't reexported by default. +this makes attempting to enumerate them a type error, rather than runtime non-termination. +See the source of "Data.Enumerate.Example" for an example. + -} -module Data.Enumerate +module Data.Enumerate --TODO rename to Enumerable ( module Data.Enumerate.Types , module Data.Enumerate.Reify - -- , module Data.Enumerate.Domain - , module Data.Enumerate.Map - ) where + -- , module Data.Enumerate.Domain + , module Data.Enumerate.Map + , module Data.Enumerate.Enum + ) where import Data.Enumerate.Types import Data.Enumerate.Reify -- import Data.Enumerate.Domain import Data.Enumerate.Map +import Data.Enumerate.Enum
+ sources/Data/Enumerate/Enum.hs view
@@ -0,0 +1,94 @@+{-# LANGUAGE ScopedTypeVariables #-} + +{-| + +usage: + +@ +data A = ... + +instance 'Bounded' A where + minBound = 'minBound_enumerable' array_A + maxBound = 'maxBound_enumerable' array_A + +instance 'Enum' A where + toEnum = 'toEnum_enumerable' array_A + fromEnum = 'fromEnum_enumerable' table_A + +-- CAF +array_A :: 'Array' Int A +array_A = 'array_enumerable' + +-- CAF +table_A :: 'Map' A Int +table_A = 'table_enumerable' + +-- we must pass in <https://wiki.haskell.org/Constant_applicative_form CAF>s +-- (i.e. expressions that are top-level and unconstrained), +-- which will be shared between all calls to minBound/maxBound/toEnum/fromEnum. +-- TODO must we? +@ + +--TODO template-haskell + +(also see the source of "Data.Enumerate.Example") + +-} +module Data.Enumerate.Enum + ( minBound_enumerable + , maxBound_enumerable + + , toEnum_enumerable + , fromEnum_enumerable + + , array_enumerable + , table_enumerable + ) where + +import Data.Enumerate.Types + +import Numeric.Natural +import qualified Data.Array as Array +import Data.Array (Array, (!)) +import qualified Data.Map as Map +import Data.Map (Map) + + +minBound_enumerable :: forall a. (Enumerable a) => Array Int a -> a +minBound_enumerable as = (as ! 0) --TODO safe get: (__fromJust__ "minBound") +{-# INLINE minBound_enumerable #-} + +maxBound_enumerable :: forall a. (Enumerable a) => Array Int a -> a +maxBound_enumerable as = (as ! (n-1)) --TODO safe get: (__fromJust__ "maxBound") + where n = nat2int $ cardinality ([] :: [a]) +{-# INLINE maxBound_enumerable #-} + + +toEnum_enumerable :: forall a. (Enumerable a) => Array Int a -> (Int -> a) +toEnum_enumerable as = \i -> (as ! i) -- i.e. (!) --TODO safe get: (__fromJust__ "toEnum") +{-# INLINE toEnum_enumerable #-} + +fromEnum_enumerable :: forall a. (Enumerable a, Ord a) => Map a Int -> (a -> Int) +fromEnum_enumerable as = \x -> (__fromJust__ "fromEnum") (Map.lookup x as) +{-# INLINE fromEnum_enumerable #-} + + +--TODO Nat ==> Int +array_enumerable :: forall a. (Enumerable a) => Array Int a --TODO +array_enumerable = Array.listArray (0, n - 1) enumerated --TODO is array efficient? + where n = nat2int $ cardinality ([] :: [a]) + +table_enumerable :: forall a. (Enumerable a, Ord a) => Map a Int +table_enumerable = Map.fromList (zip enumerated [0 .. n - 1]) + where n = nat2int $ cardinality ([] :: [a]) + + +__fromJust__ :: String -> Maybe a -> a +__fromJust__ name = maybe (__bug__ name) id + +__bug__ :: String -> a +__bug__ name = error (name ++ ": invalid Enumerable instance") +--TODO print typerep; add constraint, all types are Typeable + +nat2int :: Natural -> Int +nat2int = fromInteger . fromIntegral
sources/Data/Enumerate/Example.hs view
@@ -1,18 +1,32 @@ {-# LANGUAGE LambdaCase, DeriveGeneric, DeriveAnyClass #-} +{-# LANGUAGE FlexibleInstances #-} module Data.Enumerate.Example where import Data.Enumerate -import System.Environment (getArgs) +import Data.Array (Array) +import Data.Map (Map) + +--import System.Environment (getArgs) import Data.Void (Void) import GHC.Generics (Generic) -main = mainWith =<< getArgs +-- main = mainWith =<< getArgs +-- +-- mainWith = \case +-- _ -> do -mainWith = \case - _ -> traverse print demoEnumerated +main = do + putStrLn "" + traverse print demoEnumerated + putStrLn "" + print $ (minBound :: Demo Bool) + print $ (maxBound :: Demo Bool) + putStrLn "" + print $ demoEnumerated == [minBound..maxBound] + {- | (for documentation) demonstrates: empty type, unit type, product type, sum type, type variable. @@ -20,32 +34,48 @@ with @\{\-\# LANGUAGE DeriveGeneric, DeriveAnyClass \#\-\}@, the derivation is a one-liner: @ -data DemoEnumerable a = ... deriving (Show,Generic,Enumerable) +data Demo a = ... deriving (Show,Generic,Enumerable) @ -} -data DemoEnumerable a - = DemoEnumerable0 Void - | DemoEnumerable1 - | DemoEnumerable2 Bool (Maybe Bool) - | DemoEnumerable3 a - deriving (Show,Generic,Enumerable) +data Demo a + = Demo0 Void + | Demo1 + | Demo2 Bool (Maybe Bool) + | Demo3 a + deriving (Show,Eq,Ord,Generic,Enumerable) {- | (for documentation) @demoEnumerated = enumerated@ >>> traverse print demoEnumerated -DemoEnumerable1 -DemoEnumerable2 False Nothing -DemoEnumerable2 False (Just False) -DemoEnumerable2 False (Just True) -DemoEnumerable2 True Nothing -DemoEnumerable2 True (Just False) -DemoEnumerable2 True (Just True) -DemoEnumerable3 False -DemoEnumerable3 True +Demo1 +Demo2 False Nothing +Demo2 False (Just False) +Demo2 False (Just True) +Demo2 True Nothing +Demo2 True (Just False) +Demo2 True (Just True) +Demo3 False +Demo3 True -} -demoEnumerated :: [DemoEnumerable Bool] +demoEnumerated :: [Demo Bool] demoEnumerated = enumerated + +instance Bounded (Demo Bool) where + minBound = minBound_enumerable array_DemoBool + maxBound = maxBound_enumerable array_DemoBool + +instance Enum (Demo Bool) where + toEnum = toEnum_enumerable array_DemoBool + fromEnum = fromEnum_enumerable table_DemoBool + +-- CAF +array_DemoBool :: Array Int (Demo Bool) +array_DemoBool = array_enumerable + +-- CAF +table_DemoBool :: Map (Demo Bool) Int +table_DemoBool = table_enumerable