[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