Replies: 2 comments 2 replies
-
I have now implemented this, using the DCG non-terminal :- use_module(library(error)). :- meta_predicate(if__(1, 2, 2, ?, ?)). if__(If_1, Then, Else) --> { call(If_1, T) }, ( { T == true } -> Then ; { T == false } -> Else ; { must_be(boolean, T) } ). With this building block, we can write: :- use_module(library(dcgs)). :- use_module(library(reif)). :- use_module(library(clpz)). clpz:monotonic. compression([]) --> []. compression([L|Ls]) --> compression_(Ls, L). compression_([], L) --> [#L]. compression_([L|Ls], L0) --> if__(clpz_t(#L #= #L0 + 1), more_compression(Ls, L, L0), ([#L0], compression([L|Ls]))). more_compression([], L, L0) --> finish_run(L0, L). more_compression([M|Ms], L, L0) --> if__(clpz_t(#M #= #L + 1), more_compression(Ms, M, L0), (finish_run(L0, L), compression([M|Ms]))). finish_run(L0, L) --> if__(clpz_t(#L #= #L0 + 1), [#L0,#L], [L0-L]). Yielding for example: ?- phrase(compression([3,4,6,7,8,9,10,15,16,17,20,22,23,24,25]), Cs). Cs = [#3,#4,6-10,15-17,#20,22-25]. |
Beta Was this translation helpful? Give feedback.
1 reply
-
This was a fun puzzle! I tried solving the problem in reverse, using your :- use_module(library(reif)).
:- use_module(library(clpz)).
:- use_module(library(dcgs)).
:- use_module(library(lists)).
:- use_module(library(error)).
clpz:monotonic.
if__(If_1, Then, Else) -->
{ call(If_1, T) },
( { T == true } -> Then
; { T == false } -> Else
; { must_be(boolean, T) }
).
range(X, Y) --> { #X #=< #Y }, [X], if__(#=(X, Y), [], ({#X1 #= #X + 1}, range(X1, Y))).
expansion([]) --> [].
expansion([L|Ls]) --> expand_(L, _, I), expansion_(Ls, I).
expansion_([], _) --> [].
expansion_([L|Ls], I0) --> expand(L, I0, I), expansion_(Ls, I).
expand(Item, I0, I) --> expand_(Item, X, I), { #X #\= #I0 + 1 }.
expand_(#X, X, X) --> [X].
expand_(X-Y, X, Y) --> { #X #< #Y }, range(X, Y). It seems to work mostly the same, though my implementation doesn't quite work when trying to use iterative deepening: ?- length(X, L), phrase(expansion(X), Y).
X = [], L = 0, Y = []
; X = [#_A], L = 1, Y = [_A]
; ^C error('$interrupt_thrown',repl/0). Addendum: made this cmp(X, Y, Lt, Eq, Gt) --> if__(#<(X, Y), Lt, if__(#=(X, Y), Eq, Gt)). |
Beta Was this translation helpful? Give feedback.
1 reply
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
-
Dear all,
today I came across an interesting question: https://stackoverflow.com/questions/78401978/prolog-compress-a-list-that-contains-segments-of-continuous-numbers-to-a-list-w
It is phrased quite imperatively and a bit hard to understand as "Compressing a list of integers to a compressed list. List contains segments of continuous integers. A segment with length greater than 2 will be encoded to list
[start, end]
, end is inclusive. If the length is not greater than 2 will be kept no change."An example is also specified:
I used this opportunity to try out a few of the constructs we have available in Scryer Prolog, as currently the only Prolog system that provides them by default, notably
library(reif)
and the new predicateclpz_t/2
thanks to @librarianmage.The solution I came up with is:
Note that I am using a clean representation for the second argument: I use the prefix operator
#
to mark integers, so that we can symbolically distinguish them from ranges of the formStart-End
. With this representation, I get:One very nice property of the code is that we can also use it in other directions and modes, for instance we can ask the most general query:
We can also try different search strategies, for example iterative deepening:
Using iterative deepening, we can use the same code to find a list that results in a given "compressed" list:
We get all this generality by construction, because only pure monotonic constructs are used in the code. This ensures that the code yields correct results in all usage modes.
I leave finding a better name for the predicate as a challenge.
One other point I noticed: I think this solution would benefit from a DCG non-terminal
if__//3
that is analogous toif_/3
, except that it can be used within DCGs. I think such a non-terminal would yield a shorter and more elegant solution in this case, and I would greatly appreciate any feedback and help with these issues.Thank you a lot, and enjoy!
Markus
Beta Was this translation helpful? Give feedback.
All reactions