diff --git a/README b/README
--- a/README
+++ b/README
@@ -20,153 +20,186 @@
 
 Daily for 10 occurrences:
 
-> take 10 $ recur daily `begin` sep1997
+> take 10 $ starting sep1997 $ recur daily
 
 Daily until Dec. 24, 1997:
 
-> takeWhile (<= dec1997) $ recur daily `begin` sep1997
+> takeWhile (<= dec1997) $ starting sep1997 $ recur daily
 
 Every other day - forever:
 
-> recur daily `by` 2 `begin` sep1997
+> starting sep1997 $ recur daily `by` 2
 
 Every 10 days, 5 occurrences:
 
-> take 5 $ recur daily `by` 10 `begin` sep1997
+> take 5 $ starting sep1997 $ recur daily `by` 10
 
 Every day in January, for 3 years:
 
-> takeWhile (<= jan2000) $ recur yearly `starting` jan1998 $
->   enumMonths [January] >=>
->   filterWeekDays [Monday .. Sunday]
+> takeWhile (<= jan2000) $ starting jan1998 $
+>   recur yearly
+>   >==> enum (Months [January])
+>   >==> filter (WeekDays [Monday .. Sunday])
 
-> takeWhile (<= jan2000) $ recur daily `starting` jan1998 $
->   enumMonths [January]
+> takeWhile (<= jan2000) $ starting jan1998 $
+>   recur daily 
+>   >==> enum (Months [January])
 
 Weekly for 10 occurrences:
 
-> take 10 $ recur weekly `begin` sep1997
+> take 10 $ starting sep1997 $ recur weekly
 
 Weekly until Dec. 24, 1997:
 
-> takeWhile (<= dec1997) $ recur weekly `withStartOfWeek` Sunday `begin` sep1997
+> takeWhile (<= dec1997) $ starting sep1997 $
+>   recur weekly `withStartOfWeek` Sunday
 
 Every other week - forever:
 
-> recur weekly `by` 2 `begin` sep1997
+> starting sep1997 $ recur weekly `by` 2
 
 Weekly on Tuesday and Thursday for five weeks:
 
-> takeUntil (<= oct1997) $ recur weekly `withStartOfWeek` Sunday `starting` sep1997 $
->   enumWeekDaysInWeek [Tuesday, Thursday]
+> takeUntil (<= oct1997) $ starting sep1997 $
+>   recur weekly `withStartOfWeek` Sunday
+>   >==> enum (WeekDaysInWeek [Tuesday, Thursday])
 
 or
 
-> take 10 $ recur weekly `withStartOfWeek` Sunday `starting` sep1997 $
->   enumWeekDaysInWeek [Tuesday, Thursday]
+> take 10 $ starting sep1997 $
+>   recur weekly `withStartOfWeek` Sunday
+>   >==> enum (WeekDaysInWeek [Tuesday, Thursday])
 
 Every other week (Monday, Wednesday, Firday) until Dec. 24, 1997:
 
-> takeWhile (<= dec1997) $ recur weekly `withStartOfWeek` Sunday `by` 2 `starting` sep1997$
->   enumWeekDaysInWeek [Monday, Wednesday, Friday] >=>
+> takeWhile (<= dec1997) $ starting sep1997 $
+>   recur weekly `withStartOfWeek` Sunday `by` 2
+>   >==> enum (WeekDaysInWeek [Monday, Wednesday, Friday])
 
 > Every other week on Tuesday and Thursday, for 8 occurrences:
 
-> take 8 $ recur weekly `withStartOfWeek` Sunday `by` 2 `starting` sep1997 $
->   enumWeekDaysInWeek [Tuesday, Thursday]
+> take 8 $ starting sep1997 $
+>   recur weekly `by` 2 `withStartOfWeek` Sunday
+>   >==> enum (WeekDaysInWeek [Tuesday, Thursday])
 
 Monthly on the first Friday for 10 occurrences:
 
-> take 10 $ recur monthly `starting` sep1997 $
->   enumWeekDaysInMonth [Friday] >=>
->   nthWeekDayOfMonth [1]
+> take 10 $ starting sep1997 $
+>   recur monthly
+>   >==> enum (WeekDaysInMonth [Friday])
+>   >==> select (WeekDaysInMonth [1])
 
 Monthly on the first Friday until Dec. 24, 1997
 
-> takeWhile (<= dec1997) $ recur monthly `starting` sep1997 $
->   enumWeekDaysInMonth [Friday] >=>
->   nthWeekDayOfMonth [1]
+> takeWhile (<= dec1997) $ starting sep1997 $
+>   recur monthly
+>   >==> enum (WeekDaysInMonth [Friday])
+>   >==> select (WeekDaysInMonth [1])
 
 Every other month on the first and last Sunday of the month for 10 occurrences:
 
-> take 10 $ recur monthly `by` 2 `starting` sep1997 $
->   enumWeekDaysInMonth [Sunday] >=>
->   nthWeekDayOfMonth [1,-1]
+> take 10 $ starting sep1997 $
+>   recur monthly
+>   >==> enum (WeekDaysInMonth [Sunday])
+>   >==> select (WeekDaysInMonth [1,-1])
 
 Monthly on the second-to-last Monday of the month for 6 months:
 
-> take 6 $ recur monthly `starting` sep1997 $
->   enumWeekDaysInMonth [Monday] >=>
->   nthWeekDayOfMonth [-2]
+> take 6 $ starting sep1997 $
+>   recur monthly
+>   >==> enum (WeekDaysInMonth [Monday])
+>   >==> select (WeekDaysInMonth [-2])
 
 Monthly on the third-to-last day of the month, forever:
 
-> recur monthly `starting` sep1997 $ enumDays [-3]
+> starting sep1997 $
+>   recur monthly
+>   >==> enum (Days [-3])
 
 Monthly on the 2nd and 15th of the month for 10 occurrences:
 
-> take 10 $ recur monthly `starting` sep1997 $ enumDays [2,15]
+> take 10 $ starting sep1997 $
+>   recur monthly
+>   >==> enum (Days [2,15])
 
 Monthly on the first and last day of the month for 10 occurrences:
 
-> take 10 $ recur monthly `starting` sep1997 $ enumDays [1,-1]
+> take 10 $ starting sep1997 $
+>   recur monthly
+>   >==> enum (Days [1,-1])
 
 Every 18 months on the 10th thru 15th of the month for 10 occurrences:
 
-> take 10 $ recur monthly `by` 18 `starting` sep1997 $ enumDays [10 .. 15]
+> take 10 $ starting sep1997 $
+>   recur monthly
+>   >==> enum (Days [10 .. 15])
 
 Every Tuesday, every other month:
 
-> recur monthly `by` 2 `starting` sep1997 $ enumWeekDaysInMonth [Tuesday]
+> starting sep1997 $
+>   recur monthly `by` 2
+>   >==> enum (WeekDaysInMonth [Tuesday])
 
 Yearly in June and July for 10 occurrences:
 
-> take 10 $ recur yearly `starting` sep1997 $ enumMonths [June, July]
+> take 10 $ starting sep1997 $
+>   recur yearly
+>   >==> enum (Months [June, July])
 
 Every other year on January thru March for 10 occurrences:
 
-> take 10 $ recur yearly `by` 2 `starting` mar1997 $ 
->   enumMonths [January .. March] >=>
->   enumWeekDaysInMonth [Monday .. Sunday]
+> take 10 $ starting mar1997 $
+>   recur yearly `by` 2
+>   >==> enum (Months [January .. March])
+>   >==> enum (WeekDaysInMonth [Monday .. Sunday])
 
 Every third year on the 1st, 100th, and 200th day for 10 occurrences:
 
-> take 10 $ recur yearly `by` 3 `starting` sep1997 $
->   enumYearDays [1,100,200]
+> take 10 $ starting sep1997 $
+>   recur yearly `by` 3
+>   >==> enum (YearDays [1,100,200])
 
 Every 20th Monday of the year, forever:
 
-> recur monthly `starting` sep1997 $ 
->   enumWeekDaysInMonth [Monday] >=>
->   nthWeekDay [20]
+> starting sep1997 $
+>   recur montly
+>   >==> enum (WeekDaysInMonth [Monday])
+>   >==> select (WeekDays [20])
 
 Monday of week number 20, forever:
 
-> recur yearly `starting` mar1997 $
->   enumWeekNumbers [20] >=>
->   filterWeekDays [Monday]
+> starting mar1997 $
+>   recur yearly
+>   >==> enum (Weeks [20])
+>   >==> filter (WeekDays [Monday])
 
 or
 
-> recur weekly `starting` mar1997 $
->  filterWeekNumbers [20] >=>
->  filterWeekDays [Monday]
+> starting mar1997 $
+>   recur weekly
+>   >==> filter (Weeks [20])
+>   >==> filter (WeekDays [Monday])
 
 Every Thursday in March, forever:
 
-> recur yearly `starting` mar1997 $
->   enumMonths [March] >=>
->   enumWeekDaysInMonth [Thrusday]
+> starting mar1997 $
+>   recur yearly
+>   >==> enum (Months [March])
+>   >==> enum (WeekDaysInMonth [Thursday])
 
 Every Thursday, but only during June thru August, forever:
 
-> recur yearly `starting` mar1997 $
->   enumMonths [June .. August] >=>
->   enumWeekDaysInMonth [Thursday]
+> starting mar1997 $
+>   recur yearly
+>   >==> enum (Months [June .. August])
+>   >==> enum (WeekDaysInMonth [Thursday])
 
-Firday the 13th, Forever:
+Friday the 13th, Forever:
 
-> recur monthly `starting` sep1997 $ enumDays [13] >=> filterWeekDays [Friday]
+> starting sep1997
+>   recur monthly
+>   >==> enum (Days [13])
+>   >==> filter (WeekDays [Friday])
 
 The first Saturday that follows the first Sunday of the month, forever:
 
@@ -177,65 +210,81 @@
 U.S. Presidential Election Day:
 Every 4 years, the first Tuesday after a Monday in November, forever:
 
-> recur yearly `by` 4 `starting` nov1996 $
->   enumMonths [November] >=>
->   enumDays [2 .. 8] >=>
->   filterWeekDays [Tuesday]
+> starting nov1996 $
+>   recur yearly `by` 4
+>   >==> enum (Months [November])
+>   >==> enum (Days [2 .. 8])
+>   >==> filter (WeekDays [Tuesday])
 
 The third instance into the month of one of Tuesday, Wednesday, or Thursday, for the next 3 months.
 
-> take 3 $ recur monthly `starting` sep1997 $
->   enumWeekDaysInMonth [Tuesday .. Thursday] >=>
->   nthWeekDayOfMonth [3]
+> take 3 $ starting sep1997 $
+>   recur monthly
+>   >==> enum (WeekDaysInMonth [Tuesday .. Thursday])
+>   >==> select (WeekDaysInMonth [3])
 
 The second-to-last weekday of the month:
 
-> recur monthly `starting` sep1997 $
->   enumWeekDaysOfMonth [Monday .. Friday] >=>
->   nthWeekDayOfMonth [-2]
+> starting sep1997 $
+>   recur monthly
+>   >==> enum (WeekDaysInMonth [Monday .. Friday])
+>   >==> select (WeekDaysInMonth [-2])
 
 Every 3 hours from 9:00 AM to 5:00 PM on a specific day:
 
 > takeWhile (<= addSeconds sep1997 (8 * oneHour)) $ 
->   recur hourly `by` 3 `begin` sep1997
+>   starting sep1997 $
+>   recur hourly `by` 3
 
 Every 15 minutes for 6 occurrences:
 
-> take 6 $ recur minutely `by` 15 `begin` sep1997
+> take 6 $ starting sep1997 $
+>   recur minutely `by` 15
 
-Every hour and a hald for 4 occurrences:
+Every hour and a half for 4 occurrences:
 
-> take 4 $ recur minutely `by` 90 `begin` sep1997
+> take 4 $ starting sep1997 $ recur minutely `by` 90
 
 Every 20 minutes from 9:00 AM to 4:40 PM every day:
 
-> recur daily `starting` sep1997 $
->   enumHours [9 .. 16] >=>
->   enumMinutes [0,20,40]
+> staring sep1997 $
+>   recur daily $
+>   >==> enum (Hours [9 .. 16])
+>   >==> enum (Minutes [0,20,40])
 
 or
 
-> recur minutely `by` 20 `starting` sep1997 $ enumHours [9 .. 16]
+> starting sep1997 $
+>   recur minutely `by` 20
+>   >==> enum (Hours [9 .. 16])
 
 The following two examples will generate different results due to changes in the start of the week.
 
-> take 4 $ recur weekly `by` 2 `withStartOfWeek` Monday $
->   enumWeekDaysInWeek [Tuesday,Sunday]
+> take 4 $
+>   recur weekly `by` 2 `withStartOfWeek` Monday
+>   >==> enum (WeekDaysInWeek [Tuesday, Sunday])
 
 vs
 
-> take 4 $ recur weekly `by` 2 `withStartOfWeek` Sunday $
->   enumWeekDaysInWeek [Tuesday,Sunday]
+> take 4 $
+>   recur weekly `by` 2 `withStartOfWeek` Sunday
+>   >==> enum (WeekDaysInWeek [Tuesday, Sunday])
 
 An example where an invalid date (Feb. 30) is ignored:
 
-> take 5 $ recur monthly `starting` jan2000 $ enumDays [15,30]
+> take 5 $ starting jan2000 $
+>   recur monthly
+>   >==> enum (Days [15,30])
 
 The 15th and the 30th of the month, forever:
 
-> recur monthly `starting` sep1997 $ enumDays [15,30]
+> starting sep1997 $
+>   recur monthly
+>   >==> enum (Days [15,30])
 
 The 15th and the 30th of the month, but only during the work week:
-> recur monthly `starting` sep1997 $
->   enumDays [15,30] >=>
->   filterWeekDays [Monday .. Friday]
+
+> starting sep1997 $
+>   recur monthly
+>   >==> enum (Days [15,30])
+>   >==> filter (WeekDays [Monday .. Friday])
diff --git a/src/Data/Time/Calendar/Month.hs b/src/Data/Time/Calendar/Month.hs
--- a/src/Data/Time/Calendar/Month.hs
+++ b/src/Data/Time/Calendar/Month.hs
@@ -18,7 +18,7 @@
     | October
     | November
     | December
-  deriving (Show, Eq, Ord, Bounded)
+  deriving (Read, Show, Eq, Ord, Bounded)
 
 instance Enum Month where
   fromEnum January   = 1
diff --git a/src/Data/Time/Calendar/WeekDay.hs b/src/Data/Time/Calendar/WeekDay.hs
--- a/src/Data/Time/Calendar/WeekDay.hs
+++ b/src/Data/Time/Calendar/WeekDay.hs
@@ -13,4 +13,4 @@
     | Friday 
     | Saturday 
     | Sunday
-  deriving (Show, Eq, Ord, Enum, Bounded)
+  deriving (Read, Show, Eq, Ord, Enum, Bounded)
diff --git a/src/Data/Time/Moment.hs b/src/Data/Time/Moment.hs
--- a/src/Data/Time/Moment.hs
+++ b/src/Data/Time/Moment.hs
@@ -4,7 +4,7 @@
     )
   where
 
+import Data.Time.Moment.FutureMoments as ReExport
 import Data.Time.Moment.Interval as ReExport
 import Data.Time.Moment.Moment as ReExport
 import Data.Time.Moment.StartOfWeek as ReExport
-import Data.Time.Moment.UTC as ReExport
diff --git a/src/Data/Time/Moment/FutureMoments.hs b/src/Data/Time/Moment/FutureMoments.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Time/Moment/FutureMoments.hs
@@ -0,0 +1,336 @@
+module Data.Time.Moment.FutureMoments
+    (
+      FutureMoments -- abstract, instances: Eq, Ord, Show
+
+      -- * Drive the Moment computation
+    , iterateFutureMoments
+
+    , enumMonths
+    , enumWeeks
+    , enumDays
+    , enumWeekDaysInWeek
+    , enumWeekDaysInMonth
+    , enumYearDays
+    , enumHours
+    , enumMinutes
+    , enumSeconds
+
+    , nthMonth
+    , nthDay
+    , nthWeek
+    , nthWeekDay
+    , nthWeekDayOfWeek
+    , nthWeekDayOfMonth
+    , nthYearDay
+    , nthHour
+    , nthMinute
+    , nthSecond
+
+    , filterMonths
+    , filterWeeks
+    , filterDays
+    , filterWeekDays
+    , filterYearDays
+    , filterHours
+    , filterMinutes
+    , filterSeconds
+
+    )
+  where
+
+import Control.Monad.Reader
+import Data.Maybe (fromMaybe, mapMaybe)
+import Data.List
+import Data.List.Ordered as O
+import Data.Time.Calendar.Month
+import Data.Time.Calendar.WeekDay
+import Data.Time.CalendarTime hiding (withDay)
+import Data.Time.Moment.Moment
+
+type FutureMoments a = Reader (InitialMoment a) [a]
+
+iterateFutureMoments :: 
+  Moment a  => 
+  InitialMoment a
+  -> ([a] -> FutureMoments a)
+  -> [a]
+iterateFutureMoments im sch = runReader (iterateInitialMoment >>= sch) im
+  where
+    iterateInitialMoment :: Moment a => FutureMoments a
+    iterateInitialMoment = do
+      im <- ask
+      return $ iterate (next (interval im) (period im)) (moment im)
+
+-- | Normalize an bounded ordinal index
+--   Pass an upper-bound 'ub' and an index 'idx'
+--   Converts 'idx' < 0 into valid 'idx' > 0 or
+--   Nothing
+normalizeOrdinalIndex :: Int -> Int -> Maybe Int
+normalizeOrdinalIndex _ 0 = Nothing
+normalizeOrdinalIndex ub idx =
+  if abs idx > ub
+    then Nothing
+    else Just $ (idx + ub') `mod` ub'
+  where
+    ub' = ub + 1
+
+enumYearDays ::
+  (CalendarTimeConvertible a, Moment a) =>
+  [Int]
+  -> [a]
+  -> FutureMoments a
+enumYearDays days as = return $ concatMap (enumYearDays' days) as
+  where
+    enumYearDays' days a = mapMaybe (withYearDay a) (days' a days)
+    days' a = mapMaybe $ normalizeOrdinalIndex (daysInYear a)
+
+enumMonths :: 
+  (CalendarTimeConvertible a, Moment a) => 
+  [Month] 
+  -> [a] 
+  -> FutureMoments a
+enumMonths months as = return $ concatMap (enumMonths' months) as
+  where
+    enumMonths' months a = mapMaybe (withMonth a) months
+
+enumWeeks ::
+  (CalendarTimeConvertible a, Moment a) =>
+  [Int]
+  -> [a]
+  -> FutureMoments a
+enumWeeks weeks as = do
+  sow <- asks startOfWeek
+  return $ concatMap (enumWeeks' sow weeks) as
+ where
+   enumWeeks' sow weeks a = mapMaybe (withWeekNumber sow a) weeks
+
+enumDays ::
+  (CalendarTimeConvertible a, Moment a) =>
+  [Int]
+  -> [a]
+  -> FutureMoments a
+enumDays days as = return $ concatMap (enumDays' days) as
+  where
+    enumDays' days a = mapMaybe (withDay a) (days' a days)
+    days' a = mapMaybe $ normalizeOrdinalIndex (lastDayOfMonth a)
+
+enumWeekDaysInWeek ::
+  (CalendarTimeConvertible a, Moment a) =>
+  [WeekDay]
+  -> [a]
+  -> FutureMoments a
+enumWeekDaysInWeek wdays as = return $ concatMap (enumWeekDays' wdays) as
+  where
+    enumWeekDays' :: (CalendarTimeConvertible a, Moment a) => [WeekDay] -> a -> [a]
+    enumWeekDays' wdays a0 = let
+      w0     = calendarWeekDay $ toCalendarTime a0
+      wdays' = dropWhile (/= w0) $ O.nubSort wdays
+      in map (advanceToWeekDay a0) wdays'
+
+enumWeekDaysInMonth ::
+  (CalendarTimeConvertible a, Moment a) =>
+  [WeekDay]
+  -> [a]
+  -> FutureMoments a
+enumWeekDaysInMonth wdays as = return $ concatMap (enumWeekDays' wdays) as
+  where
+    enumWeekDays' wdays a = let
+      mdays  = mapMaybe (withDay a) [1 .. lastDayOfMonth a]
+      in filter (flip elem wdays . calendarWeekDay . toCalendarTime) mdays
+
+enumHours ::
+  (CalendarTimeConvertible a, Moment a) =>
+  [Int]
+  -> [a]
+  -> FutureMoments a
+enumHours hours as = return $ concatMap (enumHours' hours) as
+  where
+    enumHours' hours a = mapMaybe (withHour a) (hours' a hours)
+    hours' _ = mapMaybe $ normalizeOrdinalIndex 23
+
+enumMinutes ::
+  (CalendarTimeConvertible a, Moment a) =>
+  [Int]
+  -> [a]
+  -> FutureMoments a
+enumMinutes ms as = return $ concatMap (enumMinutes' ms) as
+  where
+    enumMinutes' ms a = mapMaybe (withMinute a) (ms' a ms)
+    ms' _ = mapMaybe $ normalizeOrdinalIndex 59
+
+enumSeconds ::
+  (CalendarTimeConvertible a, Moment a) =>
+  [Int]
+  -> [a]
+  -> FutureMoments a
+enumSeconds secs as = return $ concatMap (enumSeconds' secs) as
+  where
+    enumSeconds' secs a = mapMaybe (withSecond a) (secs' a secs)
+    secs' _ = mapMaybe $ normalizeOrdinalIndex 60
+
+groupWith :: (Ord b) => (a -> b) -> [a] -> [[a]]
+groupWith f = groupBy (\a b -> f a == f b)
+
+nth :: [Int] -> [a] -> [a]
+nth ns as = map ((as !!) . pred) $ mapMaybe (normalizeOrdinalIndex (length as)) ns
+
+nth' ::
+  (Ord b) =>
+  (a -> b)
+  -> [Int]
+  -> [a]
+  -> FutureMoments a
+nth' f ns as = return $ concatMap (nth ns) $ groupWith f as
+
+nthYearDay ::
+  CalendarTimeConvertible a =>
+  [Int]
+  -> [a]
+  -> FutureMoments a
+nthYearDay = nth' $ calendarYear . toCalendarTime
+
+nthMonth ::
+  CalendarTimeConvertible a =>
+  [Int]
+  -> [a]
+  -> FutureMoments a
+nthMonth = nth' $ calendarYear . toCalendarTime
+
+nthDay ::
+  CalendarTimeConvertible a =>
+  [Int]
+  -> [a]
+  -> FutureMoments a
+nthDay = nth' $ calendarMonth . toCalendarTime
+
+nthWeek ::
+  CalendarTimeConvertible a =>
+  [Int]
+  -> [a]
+  -> FutureMoments a
+nthWeek ns as = do
+  sow <- asks startOfWeek
+  return $
+    concatMap (nth ns) $
+    groupWith (weekNumber sow . toCalendarTime) as
+
+nthWeekDayOfWeek ::
+  CalendarTimeConvertible a =>
+  [Int]
+  -> [a]
+  -> FutureMoments a
+nthWeekDayOfWeek ns as = do
+  sow <- asks startOfWeek
+  return $
+    concatMap (nth ns) $
+    concatMap (groupWith (weekNumber sow)) $
+    groupWith (calendarMonth . toCalendarTime) as
+
+nthWeekDayOfMonth ::
+  CalendarTimeConvertible a =>
+  [Int]
+  -> [a]
+  -> FutureMoments a
+nthWeekDayOfMonth = nth' $ calendarMonth . toCalendarTime
+
+nthWeekDay ::
+  CalendarTimeConvertible a =>
+  [Int]
+  -> [a]
+  -> FutureMoments a
+nthWeekDay = nth' $ calendarYear . toCalendarTime
+
+nthHour ::
+  CalendarTimeConvertible a =>
+  [Int]
+  -> [a]
+  -> FutureMoments a
+nthHour = nth' $ calendarDay . toCalendarTime
+
+nthMinute ::
+  CalendarTimeConvertible a =>
+  [Int]
+  -> [a]
+  -> FutureMoments a
+nthMinute = nth' $ calendarHour . toCalendarTime
+
+nthSecond ::
+  CalendarTimeConvertible a =>
+  [Int]
+  -> [a]
+  -> FutureMoments a
+nthSecond = nth' $ calendarMinute . toCalendarTime
+
+filterCalendarTime' ::
+  (CalendarTimeConvertible a, Eq b) =>
+  (CalendarTime -> b)
+  -> [b]
+  -> [a]
+  -> [a]
+filterCalendarTime' f xs as = filter (flip elem xs . f . toCalendarTime) as
+
+filterCalendarTime ::
+  (CalendarTimeConvertible a, Eq b) =>
+  (CalendarTime -> b)
+  -> [b]
+  -> [a]
+  -> FutureMoments a
+filterCalendarTime f xs as = return $ filterCalendarTime' f xs as
+
+filterMonths ::
+  CalendarTimeConvertible a =>
+  [Month]
+  -> [a]
+  -> FutureMoments a
+filterMonths = filterCalendarTime calendarMonth
+
+filterYearDays ::
+  CalendarTimeConvertible a =>
+  [Int]
+  -> [a]
+  -> FutureMoments a
+filterYearDays = filterCalendarTime calendarYearDay
+
+filterDays ::
+  CalendarTimeConvertible a =>
+  [Int]
+  -> [a]
+  -> FutureMoments a
+filterDays = filterCalendarTime calendarDay
+
+filterWeeks ::
+  CalendarTimeConvertible a =>
+  [Int]
+  -> [a]
+  -> FutureMoments a
+filterWeeks wks as = do
+  sow <- asks startOfWeek
+  return $ filterCalendarTime' (fromMaybe 0 . weekNumber sow) (filter (>0) wks) as
+
+filterWeekDays ::
+  CalendarTimeConvertible a =>
+  [WeekDay]
+  -> [a]
+  -> FutureMoments a
+filterWeekDays = filterCalendarTime calendarWeekDay
+
+filterHours ::
+  CalendarTimeConvertible a =>
+  [Int]
+  -> [a]
+  -> FutureMoments a
+filterHours = filterCalendarTime calendarHour
+
+filterMinutes ::
+  CalendarTimeConvertible a =>
+  [Int]
+  -> [a]
+  -> FutureMoments a
+filterMinutes = filterCalendarTime calendarMinute
+
+filterSeconds ::
+  CalendarTimeConvertible a =>
+  [Int]
+  -> [a]
+  -> FutureMoments a
+filterSeconds = filterCalendarTime calendarSecond
diff --git a/src/Data/Time/Moment/Moment.hs b/src/Data/Time/Moment/Moment.hs
deleted file mode 100644
--- a/src/Data/Time/Moment/Moment.hs
+++ /dev/null
@@ -1,224 +0,0 @@
-module Data.Time.Moment.Moment
-    (
-      -- * Moment
-      Moment (..)
-    , iterateMoments
-    , withYearDay
-    , withWeekNumber
-    , withSecond
-    , withMinute
-    , withHour
-    , withDay
-    , withMonth
-    , withYear
-    , advanceToWeekDay
-
-      -- * Initial Moment
-    , InitialMoment (..)
-
-      -- * Default Initial Moment
-    , secondly
-    , minutely
-    , hourly
-    , daily
-    , weekly
-    , monthly
-    , yearly
-
-      -- * Adjust Interval
-    , by
-      -- * Adjust Start of Week
-    , withStartOfWeek
-
-      -- * Period
-    , Period (..)
-    )
-  where
-
-import Data.Time.Calendar.Month
-import Data.Time.Calendar.OrdinalDate
-import Data.Time.Calendar.WeekDay
-import Data.Time.CalendarTime hiding (withDay)
-import qualified Data.Time.CalendarTime as CT
-import Data.Time.Moment.Interval
-import Data.Time.Moment.Private
-import Data.Time.Moment.StartOfWeek
-
-oneSecond :: Integer
-oneSecond = 1
-
-oneMinute :: Integer
-oneMinute = 60 * oneSecond
-
-oneHour :: Integer
-oneHour   = 60 * oneMinute
-
-oneDay :: Integer
-oneDay    = 24 * oneHour
-
-oneWeek :: Integer
-oneWeek   = 7  * oneDay
-
--- | The @Moment@ class is for representing a instance in time.
---
--- Instances of @Moment@ can be derived for any user-defined
--- datatype for which can satisfy the minimal complete definition.
---
--- Minimal complete definition: 'epoch', 'addSeconds', 'addMonths', 'addYears'
-
-class Moment a where
-  -- | Provide a default moment.
-  epoch      :: a
-  addSeconds :: a -> Integer -> a
-  addMonths  :: a -> Integer -> a
-  addYears   :: a -> Integer -> a
-
-  addMinutes :: a -> Integer -> a
-  addMinutes a = addSeconds a . (* oneMinute)
-  addHours   :: a -> Integer -> a
-  addHours a = addSeconds a . (* oneHour)
-  addDays    :: a -> Integer -> a
-  addDays a = addSeconds a . (* oneDay)
-  addWeeks   :: a -> Integer -> a
-  addWeeks a = addSeconds a . (* oneWeek)
-
-  -- | Produce a new @Moment@ in the future ocurring at (/interval/ * /freq/)
-  next :: Interval -> Period -> a -> a
-  next (Interval interval) freq =
-    case freq of
-      Seconds -> add oneSecond
-      Minutes -> add oneMinute
-      Hours   -> add oneHour
-      Days    -> add oneDay
-      Weeks   -> add oneWeek
-      Months  -> flip addMonths interval
-      Years   -> flip addYears interval
-    where
-      add x = flip addSeconds (interval * x)
-
-  -- | Produce a new @Moment@ in the past ocurring at (-/interval/ * /freq/)
-  prev :: Interval -> Period -> a -> a
-  prev (Interval interval) = next $ Interval (-interval)
-
--- | Produce an infinite list from an initial @Moment@ and a step function.
-iterateMoments :: Moment a => (a -> a) -> a -> [a]
-iterateMoments = iterate
-
--- | Possibly produce a 'Moment' with the given week number
-withWeekNumber :: 
-  (CalendarTimeConvertible a, Moment a) => 
-  StartOfWeek 
-  -> a 
-  -> Int 
-  -> Maybe a
-withWeekNumber _ t wk = do
-  let ct = toCalendarTime t
-  day <- fromMondayStartWeekValid (calendarYear ct) wk (fromEnum $ calendarWeekDay ct)
-  fromCalendarTime $ CT.withDay ct day
-
--- | Possibly produce a 'Moment' with the given day of the year
-withYearDay ::
-  (CalendarTimeConvertible a, Moment a) =>
-  a
-  -> Int
-  -> Maybe a
-withYearDay t yd = do
- let ct = toCalendarTime t
- day <- fromOrdinalDateValid (calendarYear ct) yd
- fromCalendarTime $ CT.withDay ct day
-
--- | Possibly produce a 'Moment' with the given second
-withSecond :: (CalendarTimeConvertible a, Moment a) => a -> Int -> Maybe a
-withSecond t s = fromCalendarTime (toCalendarTime t){calendarSecond = s}
-
--- | Possibly produce a 'Moment' with the given minute
-withMinute :: (CalendarTimeConvertible a, Moment a) => a -> Int -> Maybe a
-withMinute t m = fromCalendarTime (toCalendarTime t){calendarMinute = m}
-
--- | Possibly produce a 'Moment' with the given hour
-withHour :: (CalendarTimeConvertible a, Moment a) => a -> Int -> Maybe a
-withHour t h = fromCalendarTime (toCalendarTime t){calendarHour = h}
-
--- | Possibly produce a 'Moment' with the given month day
-withDay :: (CalendarTimeConvertible a, Moment a) => a -> Int -> Maybe a
-withDay t d = fromCalendarTime (toCalendarTime t){calendarDay = d}
-
--- | Possibly produce a 'Moment' with the given month
-withMonth :: (CalendarTimeConvertible a, Moment a) => a -> Month -> Maybe a
-withMonth t m = fromCalendarTime (toCalendarTime t){calendarMonth = m}
-
--- | Possibly produce a 'Moment' with the given year
-withYear :: (CalendarTimeConvertible a, Moment a) => a -> Integer -> Maybe a
-withYear t y = fromCalendarTime (toCalendarTime t){calendarYear = y}
-
-advanceToWeekDay :: 
-  (CalendarTimeConvertible a, Moment a) => 
-  a -> 
-  WeekDay -> 
-  a
-advanceToWeekDay t d = let
-  ct  = toCalendarTime t
-  d0  = calendarWeekDay ct
-  d'  = fromEnum d
-  d0' = fromEnum d0
-  delta = toInteger $ d' - d0' `mod` 7
-  in addDays t $ if delta == 0 then 7 else delta
-
--- | The @InitialMoment@ datatype
-
-data InitialMoment a = InitialMoment
-    { period      :: Period
-    , interval    :: Interval
-    , startOfWeek :: StartOfWeek
-    , moment      :: a
-    }
-  deriving (Show)
-
-mkIM :: Moment a => Period -> InitialMoment a
-mkIM f = InitialMoment f (toInterval 1) (StartOfWeek Monday) epoch
-
--- | Default initial moments
-
-secondly :: Moment a => InitialMoment a
-secondly = mkIM Seconds
-
-minutely :: Moment a => InitialMoment a
-minutely = mkIM Minutes
-
-hourly :: Moment a => InitialMoment a
-hourly = mkIM Hours
-
-daily :: Moment a => InitialMoment a
-daily = mkIM Days
-
-weekly :: Moment a => InitialMoment a
-weekly = mkIM Weeks
-
-monthly :: Moment a => InitialMoment a
-monthly = mkIM Months
-
-yearly :: Moment a => InitialMoment a
-yearly = mkIM Years
-
--- | Typically called infix on an existing 'InitialMoment', like:
--- 
--- > monthly `by` 2
-by :: InitialMoment a -> Integer -> InitialMoment a
-by im i = im{interval=toInterval i}
-
--- | Typically called infix on an existing 'InitialMoment', like:
---
--- > weekly `withStartOfWeek` Tuesday
-withStartOfWeek :: InitialMoment a -> WeekDay -> InitialMoment a
-withStartOfWeek im sow = im{startOfWeek=toStartOfWeek sow}
-
--- | @Period@ data type
-data Period
-    = Seconds
-    | Minutes
-    | Hours
-    | Days
-    | Weeks
-    | Months
-    | Years
-  deriving (Enum, Bounded, Eq, Ord, Show)
diff --git a/src/Data/Time/Moment/UTC.hs b/src/Data/Time/Moment/UTC.hs
--- a/src/Data/Time/Moment/UTC.hs
+++ b/src/Data/Time/Moment/UTC.hs
@@ -1,12 +1,5 @@
 module Data.Time.Moment.UTC
     (
-      secondlyUTC
-    , minutelyUTC
-    , hourlyUTC
-    , dailyUTC
-    , weeklyUTC
-    , monthlyUTC
-    , yearlyUTC
     )
   where
 
@@ -18,26 +11,3 @@
   addSeconds utc i = addUTCTime (fromIntegral i) utc
   addMonths (UTCTime d t) i = UTCTime (addGregorianMonthsRollOver i d) t
   addYears (UTCTime d t) i = UTCTime (addGregorianYearsRollOver i d) t
-
--- | @InitialMoment@ defaults for @UTCTime@
-
-secondlyUTC :: InitialMoment UTCTime
-secondlyUTC = secondly
-
-minutelyUTC :: InitialMoment UTCTime
-minutelyUTC = minutely
-
-hourlyUTC :: InitialMoment UTCTime
-hourlyUTC = hourly
-
-dailyUTC :: InitialMoment UTCTime
-dailyUTC = daily
-
-weeklyUTC :: InitialMoment UTCTime
-weeklyUTC = weekly
-
-monthlyUTC :: InitialMoment UTCTime
-monthlyUTC = monthly
-
-yearlyUTC :: InitialMoment UTCTime
-yearlyUTC = yearly 
diff --git a/src/Data/Time/Recurrence.hs b/src/Data/Time/Recurrence.hs
--- a/src/Data/Time/Recurrence.hs
+++ b/src/Data/Time/Recurrence.hs
@@ -1,6 +1,7 @@
 module Data.Time.Recurrence
     (
       CalendarTime (..)
+    , M.Moment
     , module ReExport
     )
   where
@@ -8,5 +9,8 @@
 import Data.Time.CalendarTime
 import Data.Time.Calendar.Month as ReExport
 import Data.Time.Calendar.WeekDay as ReExport
-import Data.Time.Moment as ReExport
+import qualified Data.Time.Moment as M
+import Data.Time.Moment.UTC ()
+import Data.Time.Recurrence.AndThen as ReExport
 import Data.Time.Recurrence.Schedule as ReExport
+import Data.Time.Recurrence.ScheduleDetails as ReExport hiding (eval)
diff --git a/src/Data/Time/Recurrence/AndThen.hs b/src/Data/Time/Recurrence/AndThen.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Time/Recurrence/AndThen.hs
@@ -0,0 +1,11 @@
+{-# LANGUAGE FunctionalDependencies, MultiParamTypeClasses #-}
+module Data.Time.Recurrence.AndThen
+    (
+      AndThen (..)
+    )
+  where
+
+infixr 0 >==>
+
+class AndThen a b c | a b -> c where
+  (>==>) :: a -> b -> c
diff --git a/src/Data/Time/Recurrence/Schedule.hs b/src/Data/Time/Recurrence/Schedule.hs
--- a/src/Data/Time/Recurrence/Schedule.hs
+++ b/src/Data/Time/Recurrence/Schedule.hs
@@ -1,316 +1,139 @@
+{-# LANGUAGE GADTs, FlexibleInstances, FunctionalDependencies, MultiParamTypeClasses, StandaloneDeriving, UndecidableInstances #-}
 -- This module is intended to be imported @qualified!, to avoid name
 -- clashes with "Prelude" functions. eg.
 --
 -- > import qualified Data.Time.Recurrence.Schedule as S
 module Data.Time.Recurrence.Schedule
     (
-      Schedule -- abstract, instances: Eq, Ord, Show
+      -- * Schedule
+      Schedule (..)
+
+      -- * Freq
+    , Freq
+
+      -- * Function interface to Recur
     , recur
-    , starting
-    , begin
 
-    , enumMonths
-    , enumDays
-    , enumWeekDaysInWeek
-    , enumWeekDaysInMonth
-    , enumYearDays
-    , enumHours
-    , enumMinutes
-    , enumSeconds
+      -- * Adjust Interval
+    , by
+      -- * Adjust Start of Week
+    , withStartOfWeek
 
-    , nthMonth
-    , nthDay
-    , nthWeekDay
-    , nthWeekDayOfWeek
-    , nthWeekDayOfMonth
-    , nthYearDay
-    , nthHour
-    , nthMinute
-    , nthSecond
+      -- * Default Freq
+    , secondly
+    , minutely
+    , hourly
+    , daily
+    , weekly
+    , monthly
+    , yearly
 
-    , filterMonths
-    , filterDays
-    , filterWeekDays
-    , filterYearDays
-    , filterHours
-    , filterMinutes
-    , filterSeconds
+      -- * evaluate a Schedule into a function
+    , eval
+
+      -- * run an evaluated Schedule from a moment
+    , starting
     )
   where
 
-import Control.Monad.Reader
-import Data.List as L
 import Data.List.Ordered as O
-import Data.Maybe (mapMaybe)
-import Data.Time.Calendar.Month
+import Data.Time.Calendar.Month ()
 import Data.Time.Calendar.WeekDay
-import Data.Time.CalendarTime hiding (withDay)
-import Data.Time.Moment
+import Data.Time.CalendarTime
+import Data.Time.Moment hiding (interval, startOfWeek, Period(..))
+import qualified Data.Time.Moment as M (Period(..))
+import Data.Time.Recurrence.AndThen
+import Data.Time.Recurrence.ScheduleDetails hiding (eval)
+import qualified Data.Time.Recurrence.ScheduleDetails as D (eval)
 
-type Schedule a = Reader (InitialMoment a) [a]
+data Freq
+    = Secondly { interval :: Interval, startOfWeek :: StartOfWeek }
+    | Minutely { interval :: Interval, startOfWeek :: StartOfWeek }
+    | Hourly   { interval :: Interval, startOfWeek :: StartOfWeek }
+    | Daily    { interval :: Interval, startOfWeek :: StartOfWeek }
+    | Weekly   { interval :: Interval, startOfWeek :: StartOfWeek }
+    | Monthly  { interval :: Interval, startOfWeek :: StartOfWeek }
+    | Yearly   { interval :: Interval, startOfWeek :: StartOfWeek }
+  deriving (Show)
 
-runSchedule :: Schedule a -> InitialMoment a -> [a]
-runSchedule = runReader
+defaultFreq :: (Interval -> StartOfWeek -> Freq) -> Freq
+defaultFreq = flip uncurry (toInterval 1, toStartOfWeek Sunday)
 
-repeatSchedule :: 
-  Moment a  => 
-  InitialMoment a 
-  -> ([a] -> Schedule a) 
-  -> [a]
-repeatSchedule im sch = runSchedule (iterateInitialMoment >>= sch) im
-  where
-    iterateInitialMoment :: Moment a => Schedule a
-    iterateInitialMoment = do
-      im <- ask
-      return $ iterate (next (interval im) (period im)) (moment im)
+secondly :: Freq
+secondly = defaultFreq Secondly
 
-recur :: a -> a
-recur = id
+minutely :: Freq
+minutely = defaultFreq Minutely
 
--- | 'starting' is an infinite list of 'Moment's, where no 'Moment' 
--- occurrs before the 'InitialMoment'. The list is further refined
--- by the passed in function.
-starting :: (Ord a, Moment a) => 
-  InitialMoment a 
-  -> a 
-  -> ([a] -> Schedule a) 
-  -> [a]
-starting im m0 = dropWhile (< m0) . O.nub . repeatSchedule im{moment=m0}
+hourly :: Freq
+hourly = defaultFreq Hourly
 
-begin :: (Ord a, Moment a) => InitialMoment a -> a -> [a]
-begin im m0 = starting im m0 return
+daily :: Freq
+daily = defaultFreq Daily
 
--- | Normalize an bounded ordinal index
---   Pass an upper-bound 'ub' and an index 'idx'
---   Converts 'idx' < 0 into valid 'idx' > 0 or
---   Nothing
-normalizeOrdinalIndex :: Int -> Int -> Maybe Int
-normalizeOrdinalIndex _ 0 = Nothing
-normalizeOrdinalIndex ub idx =
-  if abs idx > ub
-    then Nothing
-    else Just $ (idx + ub') `mod` ub'
-  where
-    ub' = ub + 1
+weekly :: Freq
+weekly = defaultFreq Weekly
 
-enumYearDays ::
-  (CalendarTimeConvertible a, Moment a) =>
-  [Int]
-  -> [a]
-  -> Schedule a
-enumYearDays days as = return $ concatMap (enumYearDays' days) as
-  where
-    enumYearDays' days a = mapMaybe (withYearDay a) (days' a days)
-    days' a = mapMaybe $ normalizeOrdinalIndex (daysInYear a)
+monthly :: Freq
+monthly = defaultFreq Monthly
 
-enumMonths :: 
-  (CalendarTimeConvertible a, Moment a) => 
-  [Month] 
-  -> [a] 
-  -> Schedule a
-enumMonths months as = return $ concatMap (enumMonths' months) as
-  where 
-    enumMonths' months a = mapMaybe (withMonth a) months
+yearly :: Freq
+yearly = defaultFreq Yearly
 
-enumDays ::
-  (CalendarTimeConvertible a, Moment a) =>
-  [Int]
-  -> [a]
-  -> Schedule a
-enumDays days as = return $ concatMap (enumDays' days) as
-  where 
-    enumDays' days a = mapMaybe (withDay a) (days' a days)
-    days' a = mapMaybe $ normalizeOrdinalIndex (lastDayOfMonth a)
+-- | Typically called infix on an existing 'Freq', like:
+-- 
+-- > monthly `by` 2
+by :: Freq -> Integer -> Freq
+by fr i = fr{interval=toInterval i}
 
-enumWeekDaysInWeek ::
-  (CalendarTimeConvertible a, Moment a) =>
-  [WeekDay]
-  -> [a]
-  -> Schedule a
-enumWeekDaysInWeek wdays as = return $ concatMap (enumWeekDays' wdays) as
-  where
-    enumWeekDays' :: (CalendarTimeConvertible a, Moment a) => [WeekDay] -> a -> [a]
-    enumWeekDays' wdays a0 = let
-      w0     = calendarWeekDay $ toCalendarTime a0
-      wdays' = dropWhile (/= w0) $ O.nubSort wdays
-      in map (advanceToWeekDay a0) wdays'
+-- | Typically called infix on an existing 'Freq', like:
+--
+-- > weekly `withStartOfWeek` Tuesday
+withStartOfWeek :: Freq -> WeekDay -> Freq
+withStartOfWeek fr sow = fr{startOfWeek=toStartOfWeek sow}
 
-enumWeekDaysInMonth ::
-  (CalendarTimeConvertible a, Moment a) =>
-  [WeekDay]
-  -> [a]
-  -> Schedule a
-enumWeekDaysInMonth wdays as = return $ concatMap (enumWeekDays' wdays) as
-  where
-    enumWeekDays' wdays a = let
-      mdays  = mapMaybe (withDay a) [1 .. lastDayOfMonth a]
-      in filter (flip elem wdays . calendarWeekDay . toCalendarTime) mdays
-      
-enumHours ::
-  (CalendarTimeConvertible a, Moment a) =>
-  [Int]
-  -> [a]
-  -> Schedule a
-enumHours hours as = return $ concatMap (enumHours' hours) as
-  where
-    enumHours' hours a = mapMaybe (withHour a) (hours' a hours)
-    hours' _ = mapMaybe $ normalizeOrdinalIndex 23
 
-enumMinutes ::
-  (CalendarTimeConvertible a, Moment a) =>
-  [Int]
-  -> [a]
-  -> Schedule a
-enumMinutes ms as = return $ concatMap (enumMinutes' ms) as
-  where
-    enumMinutes' ms a = mapMaybe (withMinute a) (ms' a ms)
-    ms' _ = mapMaybe $ normalizeOrdinalIndex 59
-
-enumSeconds ::
-  (CalendarTimeConvertible a, Moment a) => 
-  [Int]
-  -> [a]
-  -> Schedule a
-enumSeconds secs as = return $ concatMap (enumSeconds' secs) as
-  where
-    enumSeconds' secs a = mapMaybe (withSecond a) (secs' a secs)
-    secs' _ = mapMaybe $ normalizeOrdinalIndex 60
-
-groupWith :: (Ord b) => (a -> b) -> [a] -> [[a]]
-groupWith f = groupBy (\a b -> f a == f b)
-
-nth :: [Int] -> [a] -> [a]
-nth ns as = map ((as !!) . pred) $ mapMaybe (normalizeOrdinalIndex (length as)) ns
-
-nth' ::
-  Ord b => 
-  (a -> b)
-  -> [Int]
-  -> [a]
-  -> Schedule a
-nth' f ns as = return $ concatMap (nth ns) $ groupWith f as
-
-nthYearDay ::
-  CalendarTimeConvertible a =>
-  [Int]
-  -> [a]
-  -> Schedule a
-nthYearDay = nth' $ calendarYear . toCalendarTime
-
-nthMonth ::
-  CalendarTimeConvertible a =>
-  [Int]
-  -> [a]
-  -> Schedule a
-nthMonth = nth' $ calendarYear . toCalendarTime
-
-nthDay ::
-  CalendarTimeConvertible a =>
-  [Int]
-  -> [a]
-  -> Schedule a
-nthDay = nth' $ calendarMonth . toCalendarTime
-
-nthWeekDayOfWeek ::
-  CalendarTimeConvertible a =>
-  [Int]
-  -> [a]
-  -> Schedule a
-nthWeekDayOfWeek ns as = do
-  sow <- asks startOfWeek
-  return $ 
-    concatMap (nth ns) $
-    concatMap (groupWith (weekNumber sow)) $
-    groupWith (calendarMonth . toCalendarTime) as 
-
-nthWeekDayOfMonth ::
-  CalendarTimeConvertible a =>
-  [Int]
-  -> [a]
-  -> Schedule a
-nthWeekDayOfMonth = nth' $ calendarMonth . toCalendarTime
-
-nthWeekDay ::
-  CalendarTimeConvertible a =>
-  [Int]
-  -> [a]
-  -> Schedule a
-nthWeekDay = nth' $ calendarYear . toCalendarTime
-
-nthHour ::
-  CalendarTimeConvertible a =>
-  [Int]
-  -> [a]
-  -> Schedule a
-nthHour = nth' $ calendarDay . toCalendarTime
-
-nthMinute ::
-  CalendarTimeConvertible a =>
-  [Int]
-  -> [a]
-  -> Schedule a
-nthMinute = nth' $ calendarHour . toCalendarTime
-
-nthSecond ::
-  CalendarTimeConvertible a =>
-  [Int]
-  -> [a]
-  -> Schedule a
-nthSecond = nth' $ calendarMinute . toCalendarTime
+data Schedule a where
+    Recur :: Freq -> Schedule Freq
+    And  :: Schedule Freq -> ScheduleDetails b -> Schedule (ScheduleDetails b)
 
-filterCalendarTime ::
-  (CalendarTimeConvertible a, Eq b) =>
-  (CalendarTime -> b)
-  -> [b]
-  -> [a]
-  -> Schedule a
-filterCalendarTime f xs as = return $ filter (flip elem xs . f . toCalendarTime) as
+deriving instance Show (Schedule a)
 
-filterMonths ::
-  CalendarTimeConvertible a =>
-  [Month]
-  -> [a]
-  -> Schedule a
-filterMonths = filterCalendarTime calendarMonth
+recur :: Freq -> Schedule Freq
+recur = Recur
 
-filterYearDays ::
-  CalendarTimeConvertible a =>
-  [Int]
-  -> [a]
-  -> Schedule a
-filterYearDays = filterCalendarTime calendarYearDay
+instance AndThen (Schedule Freq) (ScheduleDetails b) (Schedule (ScheduleDetails b)) where
+  (>==>) x y = And x y
 
-filterDays ::
-  CalendarTimeConvertible a =>
-  [Int]
-  -> [a]
-  -> Schedule a
-filterDays = filterCalendarTime calendarDay
+eval :: (CalendarTimeConvertible a, Ord a, Moment a) => Schedule b -> (a -> [a])
+eval (And recur details) = flip (startWith $ mkIM recur) $ D.eval details
+eval recur@(Recur _)      = start $ mkIM recur
 
-filterWeekDays ::
-  CalendarTimeConvertible a => 
-  [WeekDay]
-  -> [a]
-  -> Schedule a
-filterWeekDays = filterCalendarTime calendarWeekDay
+starting :: (CalendarTimeConvertible a, Ord a, Moment a) => a -> Schedule b -> [a]
+starting m0 sch = (eval sch) m0
 
-filterHours ::
-  CalendarTimeConvertible a =>
-  [Int]
-  -> [a]
-  -> Schedule a
-filterHours = filterCalendarTime calendarHour
+mkIM :: Moment a => Schedule Freq -> InitialMoment a
+mkIM (Recur freq) =
+    mkIM' (case freq of (Secondly _ _) -> M.Seconds
+                        (Minutely _ _) -> M.Minutes
+                        (Hourly   _ _) -> M.Hours
+                        (Daily    _ _) -> M.Days
+                        (Weekly   _ _) -> M.Weeks
+                        (Monthly  _ _) -> M.Months
+                        (Yearly   _ _) -> M.Years) (interval freq) (startOfWeek freq)
+  where
+    mkIM' :: Moment a => M.Period -> Interval -> StartOfWeek -> InitialMoment a
+    mkIM' per int sow = InitialMoment per int sow epoch
 
-filterMinutes ::
-  CalendarTimeConvertible a =>
-  [Int]
+-- | 'startWith' is an infinite list of 'Moment's, where no 'Moment' 
+-- occurrs before the 'InitialMoment'. The list is further refined
+-- by the passed in function.
+startWith :: (Ord a, Moment a) => 
+  InitialMoment a 
+  -> a 
+  -> ([a] -> FutureMoments a)
   -> [a]
-  -> Schedule a
-filterMinutes = filterCalendarTime calendarMinute
+startWith im m0 = dropWhile (< m0) . O.nub . iterateFutureMoments im{moment=m0}
 
-filterSeconds ::
-  CalendarTimeConvertible a =>
-  [Int]
-  -> [a]
-  -> Schedule a
-filterSeconds = filterCalendarTime calendarSecond
+start :: (Ord a, Moment a) => InitialMoment a -> a -> [a]
+start im m0 = startWith im m0 return
diff --git a/src/Data/Time/Recurrence/ScheduleDetails.hs b/src/Data/Time/Recurrence/ScheduleDetails.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Time/Recurrence/ScheduleDetails.hs
@@ -0,0 +1,170 @@
+{-# LANGUAGE GADTs, EmptyDataDecls, FlexibleInstances, FunctionalDependencies, MultiParamTypeClasses, RankNTypes, StandaloneDeriving, TypeSynonymInstances,UndecidableInstances #-}
+module Data.Time.Recurrence.ScheduleDetails
+    (
+      -- * ScheduleDetails
+      ScheduleDetails
+
+    , eval
+
+      -- * Functional interface to constructors
+    , enum
+    , filter
+    , select
+
+      -- * Period Filters
+    , PeriodFilter (..)
+    , EnumerablePeriodFilter (..)
+    , FilterablePeriodFilter (..)
+    , SelectablePeriodFilter (..)
+    )
+  where
+
+import Prelude hiding (filter)
+import Control.Monad ((>=>))
+import Data.Time.Calendar.Month
+import Data.Time.Calendar.WeekDay
+import Data.Time.CalendarTime
+import Data.Time.Moment hiding (Period(..))
+import Data.Time.Recurrence.AndThen
+
+data ScheduleDetails a where
+    Enumerate  :: EnumerablePeriodFilter -> ScheduleDetails EnumerablePeriodFilter
+    Filter     :: FilterablePeriodFilter -> ScheduleDetails FilterablePeriodFilter
+    Select     :: SelectablePeriodFilter -> ScheduleDetails SelectablePeriodFilter
+    EPFCons    :: ScheduleDetails EnumerablePeriodFilter -> ScheduleDetails EnumerablePeriodFilter -> ScheduleDetails EnumerablePeriodFilter
+    FPFCons    :: ScheduleDetails FilterablePeriodFilter -> ScheduleDetails FilterablePeriodFilter -> ScheduleDetails FilterablePeriodFilter
+    SPFCons    :: ScheduleDetails SelectablePeriodFilter -> ScheduleDetails SelectablePeriodFilter -> ScheduleDetails SelectablePeriodFilter
+    EPFConsFPF :: ScheduleDetails EnumerablePeriodFilter -> ScheduleDetails FilterablePeriodFilter -> ScheduleDetails FilterablePeriodFilter
+    FPFConsSPF :: ScheduleDetails FilterablePeriodFilter -> ScheduleDetails SelectablePeriodFilter -> ScheduleDetails SelectablePeriodFilter
+    EPFConsSPF :: ScheduleDetails EnumerablePeriodFilter -> ScheduleDetails SelectablePeriodFilter -> ScheduleDetails SelectablePeriodFilter
+
+deriving instance Show (ScheduleDetails a)
+
+enum :: PeriodFilter Month WeekDay NotEnumerable -> ScheduleDetails EnumerablePeriodFilter
+enum = Enumerate . EPF
+
+filter :: PeriodFilter Month NotFilterable WeekDay -> ScheduleDetails FilterablePeriodFilter
+filter = Filter . FPF
+
+select :: PeriodFilter Int Int Int -> ScheduleDetails SelectablePeriodFilter
+select = Select . SPF
+
+type BareEPF = EnumerablePeriodFilter
+type WrapEPF = ScheduleDetails EnumerablePeriodFilter
+
+instance AndThen BareEPF BareEPF WrapEPF where
+  (>==>) x y = (Enumerate x) `EPFCons` (Enumerate y)
+
+instance AndThen BareEPF WrapEPF WrapEPF where
+  (>==>) x y = (Enumerate x) `EPFCons` y
+
+instance AndThen WrapEPF WrapEPF WrapEPF where
+  (>==>) x y = x `EPFCons` y
+
+type BareFPF = FilterablePeriodFilter
+type WrapFPF = ScheduleDetails FilterablePeriodFilter
+
+instance AndThen BareFPF BareFPF WrapFPF where
+  (>==>) x y = (Filter x) `FPFCons` (Filter y)
+
+instance AndThen BareFPF WrapFPF WrapFPF where
+  (>==>) x y = (Filter x) `FPFCons` y
+
+instance AndThen WrapFPF WrapFPF WrapFPF where
+  (>==>) x y = x `FPFCons` y
+
+type BareSPF = SelectablePeriodFilter
+type WrapSPF = ScheduleDetails SelectablePeriodFilter
+
+instance AndThen BareSPF BareSPF WrapSPF where
+  (>==>) x y = (Select x) `SPFCons` (Select y)
+
+instance AndThen BareSPF WrapSPF WrapSPF where
+  (>==>) x y = (Select x) `SPFCons` y
+
+instance AndThen WrapSPF WrapSPF WrapSPF where
+  (>==>) x y = x `SPFCons` y
+
+instance AndThen WrapEPF WrapFPF WrapFPF where
+  (>==>) x y = x `EPFConsFPF` y
+
+instance AndThen WrapFPF WrapSPF WrapSPF where
+  (>==>) x y = x `FPFConsSPF` y
+
+instance AndThen WrapEPF WrapSPF WrapSPF where
+  (>==>) x y = x `EPFConsSPF` y
+
+data PeriodFilter m e f
+    = Seconds [Int]
+    | Minutes [Int]
+    | Hours [Int]
+    | Days [Int]
+    | Weeks [Int]
+    | WeekDays [f]
+    | WeekDaysInWeek [e]
+    | WeekDaysInMonth [e]
+    | Months [m]
+    | YearDays [Int]
+  deriving (Read, Show)
+
+data NotEnumerable
+data NotFilterable
+
+instance Show NotEnumerable where
+  show _ = undefined
+
+instance Read NotEnumerable where
+  readsPrec _ _ = undefined
+
+instance Show NotFilterable where
+  show _ = undefined
+
+instance Read NotFilterable where
+  readsPrec _ _ = undefined
+
+newtype EnumerablePeriodFilter = EPF { fromEPF :: PeriodFilter Month WeekDay NotEnumerable } deriving (Read, Show)
+newtype FilterablePeriodFilter = FPF { fromFPF :: PeriodFilter Month NotFilterable WeekDay } deriving (Read, Show)
+newtype SelectablePeriodFilter = SPF { fromSPF :: PeriodFilter Int Int Int } deriving (Read, Show)
+
+eval :: (CalendarTimeConvertible a, Ord a, Moment a) => ScheduleDetails b -> ([a] -> FutureMoments a)
+eval (Enumerate x) = case (fromEPF x) of
+    (Seconds ss)         -> enumSeconds ss
+    (Minutes mm)         -> enumMinutes mm
+    (Hours hh)           -> enumHours hh
+    (WeekDays _)         -> undefined
+    (WeekDaysInWeek ww)  -> enumWeekDaysInWeek ww
+    (WeekDaysInMonth ww) -> enumWeekDaysInMonth ww
+    (Days dd)            -> enumDays dd
+    (Weeks wk)           -> enumWeeks wk
+    (Months mm)          -> enumMonths mm
+    (YearDays yy)        -> enumYearDays yy
+eval (Filter x) = case (fromFPF x) of
+    (Seconds ss)        -> filterSeconds ss
+    (Minutes mm)        -> filterMinutes mm
+    (Hours hh)          -> filterHours hh
+    (WeekDays ww)       -> filterWeekDays ww
+    (WeekDaysInWeek _)  -> undefined
+    (WeekDaysInMonth _) -> undefined
+    (Days dd)           -> filterDays dd
+    (Weeks wk)          -> filterWeeks wk
+    (Months mm)         -> filterMonths mm
+    (YearDays yy)       -> filterYearDays yy
+eval (Select x) = case (fromSPF x) of
+    (Seconds ss)         -> nthSecond ss
+    (Minutes mm)         -> nthMinute mm
+    (Hours hh)           -> nthHour hh
+    (WeekDays ww)        -> nthWeekDay ww
+    (WeekDaysInWeek ww)  -> nthWeekDayOfWeek ww
+    (WeekDaysInMonth ww) -> nthWeekDayOfMonth ww
+    (Weeks wk)           -> nthWeek wk
+    (Days dd)            -> nthDay dd
+    (Months mm)          -> nthDay mm
+    (YearDays yy)        -> nthYearDay yy
+eval (EPFCons x y)    = eval x >=> eval y
+eval (FPFCons x y)    = eval x >=> eval y
+eval (SPFCons x y)    = eval x >=> eval y
+eval (EPFConsFPF x y) = eval x >=> eval y
+eval (FPFConsSPF x y) = eval x >=> eval y
+eval (EPFConsSPF x y) = eval x >=> eval y
+
+
diff --git a/tests/Tests.lhs b/tests/Tests.lhs
--- a/tests/Tests.lhs
+++ b/tests/Tests.lhs
@@ -17,8 +17,7 @@
 > import Data.Time
 > import Data.Maybe (fromJust)
 
-> import Prelude hiding (until)
-> import Control.Monad ((>=>))
+> import Prelude hiding (until, filter)
 > import Data.Time.Recurrence
 
 We are certain of the validity of the dates used, and so fromJust is safe
@@ -44,19 +43,19 @@
 > tests = 
 >      [ testGroup "RFC5445 Examples" $ zipWith (testCase . show) [1::Int ..]
 >        [ assertEqual ("Test Daily from "++ show date1 ++". 10 Occurrences") 
->            (take 10 $ recur daily `begin` date1)
->            (take 10 $ recur monthly `starting` date1 $ enumDays [2 .. 11])
+>            (take 10 $ starting date1 $ recur daily)
+>            (take 10 $ starting date1 $ recur monthly >==> enum (Days [2 .. 11]))
 >        , assertEqual ("Test Daily from "++ show date1 ++". Until "++ show date2)
->            (until date2 $ recur daily `begin` date1)
->            (until date2 $ recur monthly `starting` date1 $ enumWeekDaysInMonth [Monday .. Sunday])
+>            (until date2 $ starting date1 $ recur daily)
+>            (until date2 $ starting date1 $ recur monthly >==> enum (WeekDaysInMonth [Monday .. Sunday]))
 >        , assertBool ("Test every other day from "++ show date1 ++". Cap at 10000")
->            (checkDayDist 2 $ take 10000 $ recur daily `by` 2 `begin` date1) 
+>            (checkDayDist 2 $ take 10000 $ starting date1 $ recur $ daily `by` 2)
 >        , assertEqual ("Test every 10 days from "++ show date1 ++". 5 Occurrences")
->            (take 5 $ recur daily `by` 10 `begin` date1)
->            (take 5 $ recur yearly `starting` date1 $ enumMonths [September, October] >=> enumDays [2,12,22])
+>            (take 5 $ starting date1 $ recur $ daily `by` 10)
+>            (take 5 $ starting date1 $ recur yearly >==> enum (Months [September, October]) >==> enum (Days [2,12,22]))
 >        , assertEqual "Test every day in Jan. for 3 years"
->            (until date4 $ recur yearly `starting` date3 $ enumMonths [January] >=> enumWeekDaysInMonth [Monday .. Sunday])
->            (until date4 $ recur daily `starting` date3 $ filterMonths [January])
+>            (until date4 $ starting date3 $ recur yearly >==> enum (Months [January]) >==> enum (WeekDaysInMonth [Monday .. Sunday]))
+>            (until date4 $ starting date3 $ recur daily >==> filter (Months [January]))
 >        ]
 >      ]
 
diff --git a/time-recurrence.cabal b/time-recurrence.cabal
--- a/time-recurrence.cabal
+++ b/time-recurrence.cabal
@@ -7,7 +7,7 @@
 -- The package version. See the Haskell package versioning policy
 -- (http://www.haskell.org/haskellwiki/Package_versioning_policy) for
 -- standards guiding when and how versions should be incremented.
-Version:             0.6.1
+Version:             0.9.0
 
 -- A short (one-line) description of the package.
 Synopsis:            Generate recurring dates.
@@ -69,21 +69,23 @@
      Data.Time.Calendar.WeekDay,
      Data.Time.CalendarTime,
      Data.Time.Moment,
-     Data.Time.Moment.Interval,
-     Data.Time.Moment.StartOfWeek,
      Data.Time.Recurrence,
+     Data.Time.Recurrence.AndThen
      Data.Time.Recurrence.Schedule
+     Data.Time.Recurrence.ScheduleDetails
   Other-modules:
      Data.Time.CalendarTime.CalendarTime,
-     Data.Time.Moment.Moment,
+     Data.Time.Moment.FutureMoments
+     Data.Time.Moment.Interval,
+     Data.Time.Moment.StartOfWeek,
      Data.Time.Moment.Private,
      Data.Time.Moment.UTC
   
   -- Packages needed in order to build this package.
   Build-depends:       base >= 4 && < 5,
-                       time >= 1.4.0.1 && < 1.5,
+                       time >= 1.4 && < 1.5,
                        data-ordlist >= 0.4 && < 0.4.5,
-                       mtl >= 2.0.1.0 && < 2.1
+                       mtl >= 2.0 && < 2.2
   
   Default-Language:    Haskell98
   -- Modules not exported by this package.
@@ -98,13 +100,13 @@
   main-is:              Tests.lhs
   ghc-options:          -Wall -fno-warn-name-shadowing -fno-warn-orphans
   build-depends:        base >= 4 && < 5,
-                        time >= 1.4.0.1 && < 1.5,
-                        data-ordlist >= 0.4 && < 0.4.5,
-                        mtl >= 2.0.1.0 && < 2.1,
-                        test-framework >= 0.4.0 && < 0.5,
-                        test-framework-hunit >= 0.2.6 && < 0.3,
-                        HUnit >= 1.2.2.3 && < 1.3,
-                        old-locale >= 1.0.0.2 && < 1.1
+                        time >= 1.4 && < 1.5,
+                        data-ordlist >= 0.4 && < 0.5,
+                        mtl >= 2.0 && < 2.2,
+                        test-framework >= 0.4 && < 0.7,
+                        test-framework-hunit >= 0.2 && < 0.3,
+                        HUnit >= 1.2 && < 1.3,
+                        old-locale >= 1.0 && < 1.1
   other-modules:
     Data.Time.Recurrence
   default-language:     Haskell98
