From 5e04ecd6d4fab9e581cf65a6567ae9886f1735ff Mon Sep 17 00:00:00 2001 From: Matthew Leon Date: Sun, 28 Jan 2018 14:07:16 -0500 Subject: [PATCH 1/3] Data.Enum.Range: all elements of an enum, ordered Allows for faster default BoundedEnum implementations. --- bower.json | 6 +++++- src/Data/Enum.purs | 4 ++-- src/Data/Enum/Range.purs | 30 ++++++++++++++++++++++++++++++ 3 files changed, 37 insertions(+), 3 deletions(-) create mode 100644 src/Data/Enum/Range.purs diff --git a/bower.json b/bower.json index 1ea79a6..457a76e 100644 --- a/bower.json +++ b/bower.json @@ -20,10 +20,14 @@ "dependencies": { "purescript-either": "^3.0.0", "purescript-strings": "^3.0.0", - "purescript-unfoldable": "^3.0.0" + "purescript-unfoldable": "^3.0.0", + "purescript-arrays": "matthewleon/purescript-arrays#nonempty" }, "devDependencies": { "purescript-assert": "^3.0.0", "purescript-console": "^3.0.0" + }, + "resolutions": { + "purescript-arrays": "nonempty" } } diff --git a/src/Data/Enum.purs b/src/Data/Enum.purs index fb886e6..44396b4 100644 --- a/src/Data/Enum.purs +++ b/src/Data/Enum.purs @@ -247,14 +247,14 @@ defaultCardinality :: forall a. Bounded a => Enum a => Cardinality a defaultCardinality = Cardinality $ defaultCardinality' 1 (bottom :: a) where defaultCardinality' i = maybe i (defaultCardinality' $ i + 1) <<< succ - -- | Runs in `O(n)` where `n` is `fromEnum a` +-- | Runs in `O(n)` where `n` is `fromEnum a` defaultToEnum :: forall a. Bounded a => Enum a => Int -> Maybe a defaultToEnum n | n < 0 = Nothing | n == 0 = Just bottom | otherwise = defaultToEnum (n - 1) >>= succ - -- | Runs in `O(n)` where `n` is `fromEnum a` +-- | Runs in `O(n)` where `n` is `fromEnum a` defaultFromEnum :: forall a. Enum a => a -> Int defaultFromEnum = maybe 0 (\prd -> defaultFromEnum prd + 1) <<< pred diff --git a/src/Data/Enum/Range.purs b/src/Data/Enum/Range.purs new file mode 100644 index 0000000..11d3b4c --- /dev/null +++ b/src/Data/Enum/Range.purs @@ -0,0 +1,30 @@ +module Data.Enum.Range + ( Range + , range + , toNonEmptyArray + , cardinalityFromRange + , toEnumFromRange + ) where + +import Prelude + +import Data.Array.NonEmpty (NonEmptyArray, fromNonEmpty, index, length) +import Data.Enum (class Enum, Cardinality(..), upFromIncluding) +import Data.Maybe (Maybe) + +newtype Range a = Range (NonEmptyArray a) + +-- smart constructor for Range +range :: forall a. Bounded a => Enum a => Range a +range = Range $ fromNonEmpty $ upFromIncluding bottom + +toNonEmptyArray :: forall a. Range a -> NonEmptyArray a +toNonEmptyArray (Range xs) = xs + +-- | Runs in `O(1)` +cardinalityFromRange :: forall a. Range a -> Cardinality a +cardinalityFromRange = Cardinality <<< length <<< toNonEmptyArray + +-- | Runs in `O(1)` +toEnumFromRange :: forall a. Range a -> Int -> Maybe a +toEnumFromRange = index <<< toNonEmptyArray From 0a8ac3ab7537c9af642898242211108fe826df93 Mon Sep 17 00:00:00 2001 From: Matthew Leon Date: Sun, 28 Jan 2018 18:51:42 -0500 Subject: [PATCH 2/3] tests --- test/Main.purs | 5 ++- test/Test/Data/Enum/Range.purs | 56 ++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 test/Test/Data/Enum/Range.purs diff --git a/test/Main.purs b/test/Main.purs index f3eb9ec..6d8feed 100644 --- a/test/Main.purs +++ b/test/Main.purs @@ -7,6 +7,9 @@ import Control.Monad.Eff.Console (CONSOLE) import Test.Assert (ASSERT) import Test.Data.Enum (testEnum) +import Test.Data.Enum.Range (testRange) main :: Eff (console :: CONSOLE, assert :: ASSERT) Unit -main = testEnum +main = do + testEnum + testRange diff --git a/test/Test/Data/Enum/Range.purs b/test/Test/Data/Enum/Range.purs new file mode 100644 index 0000000..d9927d1 --- /dev/null +++ b/test/Test/Data/Enum/Range.purs @@ -0,0 +1,56 @@ +module Test.Data.Enum.Range (testRange) where + +import Prelude + +import Control.Monad.Eff (Eff) +import Control.Monad.Eff.Console (CONSOLE, log) +import Data.Array.NonEmpty (toArray) +import Data.Enum (class Enum, class BoundedEnum, Cardinality(..), cardinality, defaultFromEnum, toEnum) +import Data.Enum.Range (Range, range, toNonEmptyArray, cardinalityFromRange, toEnumFromRange) +import Data.Maybe (Maybe(..)) +import Test.Assert (ASSERT, assert) + +data T = A | B | C | D | E + +derive instance eqT :: Eq T +derive instance ordT :: Ord T + +instance enumT :: Enum T where + succ A = Just B + succ B = Just C + succ C = Just D + succ D = Just E + succ E = Nothing + + pred A = Nothing + pred B = Just A + pred C = Just B + pred D = Just C + pred E = Just D + +instance boundedT :: Bounded T where + bottom = A + top = E + +instance boundedEnumT :: BoundedEnum T where + cardinality = cardinalityFromRange rangeT + toEnum = toEnumFromRange rangeT + fromEnum = defaultFromEnum + +rangeT :: Range T +rangeT = range + +testRange :: Eff (console :: CONSOLE, assert :: ASSERT) Unit +testRange = do + log "toNonEmptyArray" + assert $ toArray (toNonEmptyArray rangeT) == [A, B, C, D, E] + + log "cardinalityFromRange" + assert $ cardinality == (Cardinality 5 :: Cardinality T) + + log "toEnumFromRange" + assert $ toEnum 0 == Just A + assert $ toEnum 1 == Just B + assert $ toEnum 2 == Just C + assert $ toEnum 3 == Just D + assert $ toEnum 4 == Just E From 8359ebb6d0b2641f877d9a00bb0330c14f611863 Mon Sep 17 00:00:00 2001 From: Matthew Leon Date: Sun, 28 Jan 2018 19:04:14 -0500 Subject: [PATCH 3/3] restore old spacing --- src/Data/Enum.purs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Data/Enum.purs b/src/Data/Enum.purs index 44396b4..fb886e6 100644 --- a/src/Data/Enum.purs +++ b/src/Data/Enum.purs @@ -247,14 +247,14 @@ defaultCardinality :: forall a. Bounded a => Enum a => Cardinality a defaultCardinality = Cardinality $ defaultCardinality' 1 (bottom :: a) where defaultCardinality' i = maybe i (defaultCardinality' $ i + 1) <<< succ --- | Runs in `O(n)` where `n` is `fromEnum a` + -- | Runs in `O(n)` where `n` is `fromEnum a` defaultToEnum :: forall a. Bounded a => Enum a => Int -> Maybe a defaultToEnum n | n < 0 = Nothing | n == 0 = Just bottom | otherwise = defaultToEnum (n - 1) >>= succ --- | Runs in `O(n)` where `n` is `fromEnum a` + -- | Runs in `O(n)` where `n` is `fromEnum a` defaultFromEnum :: forall a. Enum a => a -> Int defaultFromEnum = maybe 0 (\prd -> defaultFromEnum prd + 1) <<< pred