Prolog DCG "distilled" - Part 3 - Capturing and assembling textual elements from rules
Capturing and assembling textual elements from rules
This article builds on the previous ones, featuring a small parser for Org Mode files.I use the Clocking feature of emacs to capture how long I work on specific tasks.
However from time to time, I have to aggregate data over several files, on a monthly or yearly basis, and this is where the small tool described here can prove useful.
The code and tests for this article may be found [here].
One of the tests may be run in SWI-Prolog with those steps:
?- consult('/path/to/clocking_tool.pl').
true.
?- test_parse_clock(Start, End, Elapsed).
Start = [2020-2-5, 16:6:0], End = [2020-2-5, 17:26:0], Elapsed = 1:20 ;
false.
A version for Tau-Prolog can be found [here], and may be run online at the [tau-prolog sandbox]. See the appendix below.
?- test_parse_clock(Start, End, Elapsed).
Start = [2020-2-5, 16:6:0], End = [2020-2-5, 17:26:0], Elapsed = 1:20 ;
false.
A version for Tau-Prolog can be found [here], and may be run online at the [tau-prolog sandbox]. See the appendix below.
Defining a natural format for captured elements from rules
As I planned to reason on dates and calendars, I reviewed how the julian pack from SWI-Prolog models dates and elapsed time, having in mind to:
So I started writing a first set of DCG rules with the following heads:
- filter clocks based on calendar rules
- aggregate clocks elapsed time over lists of clocks
So I started writing a first set of DCG rules with the following heads:
yyyy_mm_dd(Date) --> ... % variable Date has format expected by julian module time_hh24_mi(Time) --> ... % variable Time has format expected by julian module timestamp([Date,Time]) --> ... % combined Date and Time duration(Duration) --> ... % duration [Hh:Mi] clock(Start, End, Elapsed) --> % aggregation of all previous elements:
% - Start and End are timestamps
% - Elapsed is a duration
yyyy_mm_dd(Date) -->
list_min1(digit, YyyyL), "-",
list_min1(digit, MmL), "-",
list_min1(digit, DdL),
{ length(YyyyL, 4), length(MmL, 2), length(DdL, 2),
number_codes(Yyyy, YyyyL), number_codes(Mm, MmL),
number_codes(Dd, DdL), Date = Yyyy-Mm-dd }.
Stepping back, this way of combining DCGs head variables to capture and aggregate matched elements from a set of rules feels natural in Prolog, as DCG rules act primarily as generators instead of functions.
As the programmer remains shielded from the mechanics of keeping track of actual matched character codes, which is done internally via the expand_term variables mechanism, the programming style with DCGs can fully retain the declarative nature of prolog.
As the programmer remains shielded from the mechanics of keeping track of actual matched character codes, which is done internally via the expand_term variables mechanism, the programming style with DCGs can fully retain the declarative nature of prolog.
Aggregating clock time over some period
The clocking tool can be sample-tested on a file with the clocks predicate, as follows:
?- clocks('20200206', Clocks), take(2, Clocks, Res).
This is achieved with the use of the noteworthy list_util module.
Aggregation over some daily, monthly or yearly period is done with a fold, using the functional programming module yall.

Comments
Post a Comment