Okay...final version attached. This one fixes the toCycle bugs and changes from Int to Integer so overflow is no longer an issue. The result of cycleFromThenTo fits what I would expect, but you are free to drop this or adapt it. cycleFrom and cycleFromTo and cycleFromThen are easy, since there is no difference between ascending and descending. Note that the returned list is never null. cycleFromThenTo can be either ascending or descending depending on the first two arguments, and it considers the first occurrence of the third argument in that direction of the cycle starting from the initial argument: *Cycle> cycleFromThenTo Monday Wednesday Tuesday [Monday] instead of
*Cycle> cycleFromThenTo Monday Wednesday Tuesday [Monday,Wednesday,Friday,Sunday,Tuesday]
This agrees with things like [1,3 .. 2] returning [1] and [3,1 .. 2] returning [3]. {- By Chris Kuklewicz <haskell@list.mightyreason.com> 3 Clause BSD license, copyright 2006 -} module Cycle (Cyclic(..)) where import System.Time import Data.Word import Data.Int default () class (Eq c,Enum c, Bounded c) => Cyclic c where cyclePeriod :: c -> Integer cyclePeriod _ = fromCycle (maxBound :: c) - fromCycle (minBound :: c) + 1 succCycle :: c -> c succCycle c | c == maxBound = minBound | otherwise = succ c predCycle :: c-> c predCycle c | c == minBound = maxBound | otherwise = pred c fromCycle :: c -> Integer fromCycle = toInteger . fromEnum toCycle :: Integer -> c toCycle = toEnum . fromInteger . (+ (fromCycle (minBound::c))) . (`mod` (cyclePeriod (undefined::c))) . (subtract (fromCycle (minBound::c))) cycleFrom :: c -> [c] cycleFrom x = map toCycle [fromCycle x ..] cycleFromTo :: c -> c -> [c] cycleFromTo x y = let xi = fromCycle x yi = fromCycle y zi = if xi > yi then yi + cyclePeriod (undefined::c) else yi in map toCycle [xi .. zi] cycleFromThen :: c -> c -> [c] cycleFromThen x y = let xi = fromCycle x yi = fromCycle y in map toCycle [xi, yi ..] cycleFromThenTo :: c -> c -> c -> [c] cycleFromThenTo x y z = let c = cyclePeriod (undefined::c) xi = fromCycle x; yi = fromCycle y; zi = fromCycle z zi' = if xi <= yi then if xi <= zi then zi else zi + c else if zi <= xi then zi else zi - c in map toCycle [xi, yi .. zi'] instance Cyclic () instance Cyclic Bool instance Cyclic Ordering instance Cyclic Int instance Cyclic Char instance Cyclic Day -- Imported from System.Time instance Cyclic Month -- Imported from System.Time instance Cyclic Int8 -- Imported from GHC.Int instance Cyclic Int64 -- Imported from GHC.Int instance Cyclic Int32 -- Imported from GHC.Int instance Cyclic Int16 -- Imported from GHC.Int instance Cyclic Word8 -- Imported from GHC.Word instance Cyclic Word64 -- Imported from GHC.Word instance Cyclic Word32 -- Imported from GHC.Word instance Cyclic Word16 -- Imported from GHC.Word