[m-rev.] for review: folding over a range of dates
Julien Fischer
jfischer at opturion.com
Tue Jan 29 11:33:12 AEDT 2013
For review by Ian.
Branches: main
Add predicates to the standard library's calendar module for folding the days
in a given range of dates.
library/calendar.m:
Add the new predicates: foldl2_days/5, foldl2_days/7 and
foldl3_days/9.
NEWS:
Announce the addition.
tests/hard_coded/Mmakefile:
tests/hard_coded/fold_days.{m,exp}:
Test the new predicates.
Julien.
diff --git a/NEWS b/NEWS
index 84c25f4..7d6114c 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,12 @@
+NEWS since Mercury 12.08
+------------------------
+
+Changes to the Mercury standard library:
+
+* We have added predicates to the calendar module for folding over the days
+ in a given range of dates: foldl_days/5, foldl2_days/7 and foldl3_days/9.
+
+
NEWS for Mercury 12.08
----------------------
diff --git a/library/calendar.m b/library/calendar.m
index 0e9d2f0..e692cc3 100644
--- a/library/calendar.m
+++ b/library/calendar.m
@@ -283,6 +283,63 @@
:- func day_duration(date, date) = duration.
%----------------------------------------------------------------------------%
+%
+% Folds over ranges of dates.
+%
+
+ % foldl_days(Pred, Start, End, !Acc):
+ % Calls Pred for each day in the range of dates from Start to End
+ % with an accumulator.
+ % Each date in the range is generated by adding a duration of one day
+ % to the previous date using the add_duration/3 predicate.
+ % Consequently, the time components of the dates in the range may
+ % differ if the time components of the given start and end times
+ % include leap seconds.
+ %
+:- pred foldl_days(pred(date, A, A), date, date, A, A).
+:- mode foldl_days(pred(in, in, out) is det, in, in, in, out) is det.
+:- mode foldl_days(pred(in, mdi, muo) is det, in, in, mdi, muo) is det.
+:- mode foldl_days(pred(in, di, uo) is det, in, in, di, uo) is det.
+:- mode foldl_days(pred(in, in, out) is semidet, in, in, in, out) is semidet.
+:- mode foldl_days(pred(in, mdi, muo) is semidet, in, in, mdi, muo) is semidet.
+:- mode foldl_days(pred(in, di, uo) is semidet, in, in, di, uo) is semidet.
+
+ % foldl2_days(Pred, Start, End, !Acc1, !Acc2):
+ % As above, but with two accumulators.
+ %
+:- pred foldl2_days(pred(date, A, A, B, B), date, date, A, A, B, B).
+:- mode foldl2_days(pred(in, in, out, in, out) is det, in, in, in, out,
+ in, out) is det.
+:- mode foldl2_days(pred(in, in, out, mdi, muo) is det, in, in, in, out,
+ mdi, muo) is det.
+:- mode foldl2_days(pred(in, in, out, di, uo) is det, in, in, in, out,
+ di, uo) is det.
+:- mode foldl2_days(pred(in, in, out, in, out) is semidet, in, in, in, out,
+ in, out) is semidet.
+:- mode foldl2_days(pred(in, in, out, mdi, muo) is semidet, in, in, in, out,
+ mdi, muo) is semidet.
+:- mode foldl2_days(pred(in, in, out, di, uo) is semidet, in, in, in, out,
+ di, uo) is semidet.
+
+ % foldl3_days(Pred, Start, End, !Acc1, !Acc2, !Acc3):
+ % As above, but with three accumulators.
+ %
+:- pred foldl3_days(pred(date, A, A, B, B, C, C), date, date,
+ A, A, B, B, C, C).
+:- mode foldl3_days(pred(in, in, out, in, out, in, out) is det, in, in,
+ in, out, in, out, in, out) is det.
+:- mode foldl3_days(pred(in, in, out, in, out, mdi, muo) is det, in, in,
+ in, out, in, out, mdi, muo) is det.
+:- mode foldl3_days(pred(in, in, out, in, out, di, uo) is det, in, in,
+ in, out, in, out, di, uo) is det.
+:- mode foldl3_days(pred(in, in, out, in, out, in, out) is semidet, in, in,
+ in, out, in, out, in, out) is semidet.
+:- mode foldl3_days(pred(in, in, out, in, out, mdi, muo) is semidet, in, in,
+ in, out, in, out, mdi, muo) is semidet.
+:- mode foldl3_days(pred(in, in, out, in, out, di, uo) is semidet, in, in,
+ in, out, in, out, di, uo) is semidet.
+
+%----------------------------------------------------------------------------%
%----------------------------------------------------------------------------%
:- implementation.
@@ -1093,5 +1150,46 @@ day_of_week_num(sunday, 6).
unix_epoch = date(1970, 1, 1, 0, 0, 0, 0).
%-----------------------------------------------------------------------------%
+
+foldl_days(Pred, !.Curr, End, !Acc) :-
+ compare(Res, !.Curr, End),
+ (
+ ( Res = (<)
+ ; Res = (=)
+ ),
+ Pred(!.Curr, !Acc),
+ add_duration(init_duration(0, 0, 1, 0, 0, 0, 0), !Curr),
+ foldl_days(Pred, !.Curr, End, !Acc)
+ ;
+ Res = (>)
+ ).
+
+foldl2_days(Pred, !.Curr, End, !Acc1, !Acc2) :-
+ compare(Res, !.Curr, End),
+ (
+ ( Res = (<)
+ ; Res = (=)
+ ),
+ Pred(!.Curr, !Acc1, !Acc2),
+ add_duration(init_duration(0, 0, 1, 0, 0, 0, 0), !Curr),
+ foldl2_days(Pred, !.Curr, End, !Acc1, !Acc2)
+ ;
+ Res = (>)
+ ).
+
+foldl3_days(Pred, !.Curr, End, !Acc1, !Acc2, !Acc3) :-
+ compare(Res, !.Curr, End),
+ (
+ ( Res = (<)
+ ; Res = (=)
+ ),
+ Pred(!.Curr, !Acc1, !Acc2, !Acc3),
+ add_duration(init_duration(0, 0, 1, 0, 0, 0, 0), !Curr),
+ foldl3_days(Pred, !.Curr, End, !Acc1, !Acc2, !Acc3)
+ ;
+ Res = (>)
+ ).
+
+%-----------------------------------------------------------------------------%
:- end_module calendar.
%-----------------------------------------------------------------------------%
diff --git a/tests/hard_coded/Mmakefile b/tests/hard_coded/Mmakefile
index b3b80be..fa65c46 100644
--- a/tests/hard_coded/Mmakefile
+++ b/tests/hard_coded/Mmakefile
@@ -109,6 +109,7 @@ ORDINARY_PROGS= \
float_map \
float_reg \
float_rounding_bug \
+ fold_days \
follow_code_bug \
follow_code_bug_2 \
foreign_and_mercury \
diff --git a/tests/hard_coded/fold_days.exp b/tests/hard_coded/fold_days.exp
new file mode 100644
index 0000000..79d1529
--- /dev/null
+++ b/tests/hard_coded/fold_days.exp
@@ -0,0 +1,30 @@
+Test 1:
+1900-02-25 00:00:00
+1900-02-26 00:00:00
+1900-02-27 00:00:00
+1900-02-28 00:00:00
+1900-03-01 00:00:00
+
+Test 2:
+2000-02-25 00:00:00
+2000-02-26 00:00:00
+2000-02-27 00:00:00
+2000-02-28 00:00:00
+2000-02-29 00:00:00
+2000-03-01 00:00:00
+
+Test 3:
+1977-02-25 00:00:00
+1977-02-26 00:00:00
+1977-02-27 00:00:00
+1977-02-28 00:00:00
+1977-03-01 00:00:00
+
+Test 4:
+1977-02-17 00:00:00
+
+Test 5:
+1977-02-17 00:00:00
+
+Test 6:
+
diff --git a/tests/hard_coded/fold_days.m b/tests/hard_coded/fold_days.m
new file mode 100644
index 0000000..b4ee965
--- /dev/null
+++ b/tests/hard_coded/fold_days.m
@@ -0,0 +1,65 @@
+:- module fold_days.
+:- interface.
+
+:- import_module io.
+
+:- pred main(io::di, io::uo) is det.
+
+:- implementation.
+
+:- import_module calendar.
+:- import_module int.
+:- import_module string.
+
+main(!IO) :-
+
+ % Test 1: 1900 was not a leap year.
+ Date1A = det_init_date(1900, february, 25, 0, 0, 0, 0),
+ Date1B = det_init_date(1900, march, 1, 0, 0, 0, 0),
+ io.write_string("Test 1:\n", !IO),
+ foldl_days(write_date, Date1A, Date1B, !IO),
+ io.nl(!IO),
+
+ % Test 2: 2000 was a leap year.
+ Date2A = det_init_date(2000, february, 25, 0, 0, 0, 0),
+ Date2B = det_init_date(2000, march, 1, 0, 0, 0, 0),
+ io.write_string("Test 2:\n", !IO),
+ foldl_days(write_date, Date2A, Date2B, !IO),
+ io.nl(!IO),
+
+ % Test 3: 1977 was not a leap year.
+ Date3A = det_init_date(1977, february, 25, 0, 0, 0, 0),
+ Date3B = det_init_date(1977, march, 1, 0, 0, 0, 0),
+ io.write_string("Test 3:\n", !IO),
+ foldl_days(write_date, Date3A, Date3B, !IO),
+ io.nl(!IO),
+
+ % Test 4: calendar dates of start and end are the same,
+ % time of start is less than that of the end.
+ Date4A = det_init_date(1977, february, 17, 0, 0, 0, 0),
+ Date4B = det_init_date(1977, february, 17, 1, 0, 0, 0),
+ io.write_string("Test 4:\n", !IO),
+ foldl_days(write_date, Date4A, Date4B, !IO),
+ io.nl(!IO),
+
+ % Test 5: calendar dates of start and end are the same,
+ % time of start is equal to that of the end.
+ Date5A = det_init_date(1977, february, 17, 0, 0, 0, 0),
+ Date5B = det_init_date(1977, february, 17, 0, 0, 0, 0),
+ io.write_string("Test 5:\n", !IO),
+ foldl_days(write_date, Date5A, Date5B, !IO),
+ io.nl(!IO),
+
+ % Test 6: calendar dates of start and end are the same,
+ % time of the start is greater than that of the end.
+ Date6A = det_init_date(1977, february, 17, 1, 0, 0, 0),
+ Date6B = det_init_date(1977, february, 17, 0, 0, 0, 0),
+ io.write_string("Test 6:\n", !IO),
+ foldl_days(write_date, Date6A, Date6B, !IO),
+ io.nl(!IO).
+
+:- pred write_date(date::in, io::di, io::uo) is det.
+
+write_date(Date, !IO) :-
+ Str = date_to_string(Date),
+ io.write_string(Str ++ "\n", !IO).
_______________________________________________
reviews mailing list
reviews at lists.mercurylang.org
http://lists.mercurylang.org/listinfo/reviews
More information about the reviews
mailing list