I need to decompress a list in prolog , like in the example below :
decode([[a,1],[b,2],[c,1],[d,3]],L).
L = [a, b, b, c, d, d, d] ;
I made this code :
divide(L,X,Y):-length(X,1),append(X,Y,L).
divide2(L,X,Y):-divide(L,[X|_],[Y|_]).
makelist(_,N,[]):- N =< 0 .
makelist(X,Y,[X|Result]):-Y1 is Y-1,makelist(X,Y1,Result).
makelist2(L,L2):-divide2(L,X,Y),makelist(X,Y,L2).
decode([],[]).
decode([H|T],L):-makelist2(H,H2),append(H2,L,L2),decode(T,L2).
and when i call
makelist2([a,3],L2).
L2 = [a,a,a].
but when i call
decode([[a,3],[b,1],[c,4]],L)
runs continuously. What am i doing wrong ?
Another variation of the theme, using a slightly modified version of Boris' repeat/3 predicate:
% True when L is a list with N repeats of X
repeat([X, N], L) :-
length(L, N),
maplist(=(X), L).
decode(Encoded, Decoded) :-
maplist(repeat, Encoded, Expanded),
flatten(Expanded, Decoded).
If Encode = [[a,1],[b,2],[c,1],[d,3]], then in the above decode/2, the maplist/3 call will yield Expanded = [[a],[b,b],[c],[d,d,d]], and then the flatten/2 call results in Decoded = [a,b,b,c,d,d,d].
In SWI Prolog, instead of flatten/2, you can use append/2 since you only need a "flattening" at one level.
EDIT: Adding a "bidirectional" version, using a little CLPFD:
rle([], []).
rle([X], [[1,X]]).
rle([X,Y|T], [[1,X]|R]) :-
X \== Y, % use dif(X, Y) here, if available
rle([Y|T], R).
rle([X,X|T], [[N,X]|R]) :-
N #= N1 + 1,
rle([X|T], [[N1,X]|R]).
This will yield:
| ?- rle([a,a,a,b,b], L).
L = [[3,a],[2,b]] ? ;
(1 ms) no
| ?- rle(L, [[3,a],[2,b]]).
L = [a,a,a,b,b] ? ;
no
| ?- rle([a,a,a,Y,Y,Z], [X, [N,b],[M,c]]).
M = 1
N = 2
X = [3,a]
Y = b
Z = c ? a
no
| ?- rle([A,B,C], D).
D = [[1,A],[1,B],[1,C]] ? ;
C = B
D = [[1,A],[2,B]] ? ;
B = A
D = [[2,A],[1,C]] ? ;
B = A
C = A
D = [[3,A]] ? ;
(2 ms) no
| ?- rle(A, [B,C]).
A = [D,E]
B = [1,D]
C = [1,E] ? ;
A = [D,E,E]
B = [1,D]
C = [2,E] ? ;
A = [D,E,E,E]
B = [1,D]
C = [3,E] ? ;
...
| ?- rle(A, B).
A = []
B = [] ? ;
A = [C]
B = [[1,C]] ? ;
A = [C,D]
B = [[1,C],[1,D]] ? ;
...
As #mat suggests in his comment, in Prolog implementations that have dif/2, then dif(X,Y) is preferable to X \== Y above.
The problem is in the order of your append and decode in the last clause of decode. Try tracing it, or even better, trace it "by hand" to see what happens.
Another approach: see this answer. So, with repeat/3 defined as:
% True when L is a list with N repeats of X
repeat(X, N, L) :-
length(L, N),
maplist(=(X), L).
You can write your decode/2 as:
decode([], []).
decode([[X,N]|XNs], Decoded) :-
decode(XNs, Decoded_rest),
repeat(X, N, L),
append(L, Decoded_rest, Decoded).
But this is a slightly roundabout way to do it. You could define a difference-list version of repeat/3, called say repeat/4:
repeat(X, N, Reps, Reps_back) :-
( succ(N0, N)
-> Reps = [X|Reps0],
repeat(X, N0, Reps0, Reps_back)
; Reps = Reps_back
).
And then you can use a difference-list version of decode/2, decode_1/3
decode(Encoded, Decoded) :-
decode_1(Encoded, Decoded, []).
decode_1([], Decoded, Decoded).
decode_1([[X,N]|XNs], Decoded, Decoded_back) :-
repeat(X, N, Decoded, Decoded_rest),
decode_1(XNs, Decoded_rest, Decoded_back).
?- decode([[a,1],[b,2],[c,1],[d,3]],L).
L = [a, b, b, c, d, d, d].
?- decode([[a,3],[b,1],[c,0],[d,3]],L).
L = [a, a, a, b, d, d, d].
?- decode([[a,3]],L).
L = [a, a, a].
?- decode([],L).
L = [].
You can deal with both direction with this code :
:- use_module(library(lambda)).
% code from Pascal Bourguignon
packRuns([],[]).
packRuns([X],[[X]]).
packRuns([X|Rest],[XRun|Packed]):-
run(X,Rest,XRun,RRest),
packRuns(RRest,Packed).
run(Var,[],[Var],[]).
run(Var,[Var|LRest],[Var|VRest],RRest):-
run(Var,LRest,VRest,RRest).
run(Var,[Other|RRest],[Var],[Other|RRest]):-
dif(Var,Other).
%end code
pack_1(In, Out) :-
maplist(\X^Y^(X = [V|_],
Y = [V, N],
length(X, N),
maplist(=(V), X)),
In, Out).
decode(In, Out) :-
when((ground(In); ground(Out1)),pack_1(Out1, In)),
packRuns(Out, Out1).
Output :
?- decode([[a,1],[b,2],[c,1],[d,3]],L).
L = [a, b, b, c, d, d, d] .
?- decode(L, [a,b,b,c,d,d,d]).
L = [[a, 1], [b, 2], [c, 1], [d, 3]] .
a compact way:
decode(L,D) :- foldl(expand,L,[],D).
expand([S,N],L,E) :- findall(S,between(1,N,_),T), append(L,T,E).
findall/3 it's the 'old fashioned' Prolog list comprehension facility
decode is a poor name for your predicate: properly done, you predicate should be bi-directional — if you say
decode( [[a,1],[b,2],[c,3]] , L )
You should get
L = [a,b,b,c,c,c].
And if you say
decode( L , [a,b,b,c,c,c] ) .
You should get
L = [[a,1],[b,2],[c,3]].
So I'd use a different name, something like run_length_encoding/2. I might also not use a list to represent individual run lengths as [a,1] is this prolog term: .(a,.(1,[]). Just use a simple term with arity 2 — myself, I like using :/2 since it's defined as an infix operator, so you can simply say a:1.
Try this on for size:
run_length_encoding( [] , [] ) . % the run-length encoding of the empty list is the empty list.
run_length_encoding( [X|Xs] , [R|Rs] ) :- % the run-length encoding of a non-empty list is computed by
rle( Xs , X:1 , T , R ) , % - run-length encoding the prefix of the list
run_length_encoding( T , Rs ) % - and recursively run-length encoding the remainder
. % Easy!
rle( [] , C:N , [] , C:N ) . % - the run is complete when the list is exhausted.
rle( [X|Xs] , C:N , [X|Xs] , C:N ) :- % - the run is complete,
X \= C % - when we encounter a break
. %
rle( [X|Xs] , X:N , T , R ) :- % - the run continues if we haven't seen a break, so....
N1 is N+1 , % - increment the run length,
rle( Xs, X:N1, T, R ) % - and recurse down.
. % Easy!
In direct answer to the original question of, What am I doing wrong?...
When I ran the original code, any expected use case "ran indefinitely" without yielding a result.
Reading through the main predicate:
decode([],[]).
This says that [] is the result of decoding []. Sounds right.
decode([H|T],L) :- makelist2(H,H2), append(H2,L,L2), decode(T,L2).
This says that L is the result of decoding [H|T] if H2 is an expansion of H (which is what makelist2 does... perhaps - we'll go over that below), and H2 appended to this result gives another list L2 which is the decoded form of the original tail T. That doesn't sound correct. If I decode [H|T], I should (1) expand H, (2) decode T giving L2, then (3) append H to L2 giving L.
So the corrected second clause is:
decode([H|T], L) :- makelist2(H, H2), decode(T, L2), append(H2, L2, L).
Note the argument order of append/3 and that the call occurs after the decode of the tail. As Boris pointed out previously, the incorrect order of append and the recursive decode can cause the continuous running without any output as append with more uninstantiated arguments generates a large number of unneeded possibilities before decode can succeed.
But now the result is:
| ?- decode([[a,3]], L).
L = [a,a,a] ? ;
L = [a,a,a,a] ? ;
...
If you try out our other predicates by hand in the Prolog interpreter, you'll find that makelist2/2 has an issue:
It produces the correct result, but also a bunch of incorrect results. Let's have a look at makelist2/2. We can try this predicate by itself and see what happens:
| ?- makelist2([a,3], L).
L = [a,a,a] ? ;
L = [a,a,a,a] ? ;
...
There's an issue: makelist2/2 should only give the first solution, but it keeps going, giving incorrect solutions. Let's look closer at makelist/2:
makelist2(L,L2) :- divide2(L,X,Y), makelist(X,Y,L2).
It takes a list L of the form [A,N], divides it (via divide2/3) into X = A and Y = N, then calls an auxiliary, makelist(X, Y, L2).
makelist(_,N,[]):- N =< 0 .
makelist(X,Y,[X|Result]):-Y1 is Y-1,makelist(X,Y1,Result).
makelist/3 is supposed to generate a list (the third argument) by replicating the first argument the number of times given in the second argument. The second, recursive clause appears to be OK, but has one important flaw: it will succeed even if the value of Y is less than or equal to 0. Therefore, even though a correct solution is found, it keeps succeeding on incorrect solutions because the base case allows the count to be =< 0:
| ?- makelist(a,2,L).
L = [a,a] ? ;
L = [a,a,a] ? ;
We can fix makelist/2 as follows:
makelist(_,N,[]):- N =< 0 .
makelist(X,Y,[X|Result]):- Y > 0, Y1 is Y-1, makelist(X,Y1,Result).
Now the code will generate a correct result. We just needed to fix the second clause of decode/2, and the second clause of makelist/3.
| ?- decode([[a,3],[b,4]], L).
L = [a,a,a,b,b,b,b]
yes
The complete, original code with just these couple of corrections looks like this:
divide(L, X, Y) :- length(X, 1), append(X, Y, L).
divide2(L, X, Y) :- divide(L, [X|_], [Y|_]).
makelist(_, N, []) :- N =< 0 .
makelist(X, Y, [X|Result]) :- Y > 0, Y1 is Y-1, makelist(X,Y1,Result).
makelist2(L, L2) :- divide2(L, X, Y), makelist(X, Y, L2).
decode([], []).
decode([H|T], L) :- makelist2(H,H2), decode(T,L2), append(H2,L2,L).
Note some simple, direct improvements. The predicate, divide2(L, X, Y) takes a list L of two elements and yields each, individual element, X and Y. This predicate is unnecessary because, in Prolog, you can obtain these elements by simple unification: L = [X, Y]. You can try this right in the Prolog interpreter:
| ?- L = [a,3], L = [X,Y].
L = [a,3]
X = a
Y = 3
yes
We can then completely remove the divide/3 and divide2/3 predicates, and replace a call to divide2(L, X, Y) with L = [X,Y] and reduce makelist2/2 to:
makelist2(L, L2) :- L = [X, Y], makelist(X, Y, L2).
Or more simply (because we can do the unification right in the head of the clause):
makelist2([X,Y], L2) :- makelist(X, Y, L2).
You could just remove makelist2/2 and call makelist/2 directly from decode/2 by unifying H directly with its two elements, [X, N]. So the original code simplifies to:
makelist(_, N, []) :- N =< 0 .
makelist(X, Y, [X|Result]) :- Y > 0, Y1 is Y-1, makelist(X,Y1,Result).
decode([], []).
decode([[X,N]|T], L) :- makelist(X, N, H2), decode(T, L2), append(H2, L2, L).
And makelist/3 can be performed a bit more clearly using one of the methods provided in the other answers (e.g., see Boris' repeat/3 predicate).
Related
Without using arithmetics (=< , =>, etc.)!
I have a few separate piles of blocks, for example two piles.
I need a way to figure out if block A sits Higher on any pile than block B.
For example:
is_on_top(Block1,Pile,Block2). %relations of blocks in a particular pile
for example:
is_bellow(a,1,b). % a is bellow b in pile number 1
is_bellow(r,2,e).
is_bellow(f,2,null). % is at top.
....
and so on.
I'm trying to figure out how to write the predicate:
is_higher(Block1,Block2):- %block1 is higher than block2 in Any line.
% to check for the same line if a block is higher than another I'm this
% is Block1 higher than Block2 in THE SAME pile.
taller(Block1, Block2) :-
is_bellow(Block2,_,Block1).
taller(Block1, Block2) :-
is_bellow(Y, I,Block1),
taller(Y, Block2).
is it possible to do it without using arithmetics?
I think I have the terminating condition.
is_higher(Block1,Block2):-
is_bellow(Block1,_,null), is_bellow(Block2,_,X).
X \= null.
is_higher(Block1,Block2):- % don't know how to continue.
From the comments:
I thought something along the lines of digging deeper on both blocks till block one is paired with null, but I cant quite get my head around it.
You are thinking along the correct lines, but your representation of the world seems to confuse you a bit. It becomes easier if we define a cleaner language for talking about blocks and their relationships.
It would have been good if you had posted a complete example. Here is the one I will be using:
is_below(a, 1, b).
is_below(b, 1, null). % topmost on pile
is_below(c, 2, d).
is_below(d, 2, e).
is_below(e, 2, f).
is_below(f, 2, null). % topmost on pile
I understand this to model the following world:
f
e
b d
a c
-----------------
pile 1 pile 2
Now let's talk about concepts related to this world. First... what even is a block? The representation is implicit, but it appears that a block is something that is on a pile. Being "on a pile" is somewhat implicit too, but it means being below something -- another block, or the special non-block atom null.
So this is a block:
% block(X): X is a block
block(X) :-
is_below(X, _Pile, _BlockOrNull).
Prolog can now enumerate blocks:
?- block(X).
X = a ;
X = b ;
X = c ;
X = d ;
X = e ;
X = f.
Note that null is not included, which is good since it is not a block.
Now, is_below complicates things because it talks about non-blocks (namely, null) and also about the numbers of piles, which we don't always need. Let's define a simpler notion of a block being directly on top of another block:
% block_on(X, Y): X is a block directly on top of block Y
block_on(X, Y) :-
is_below(Y, _Pile, X),
block(X).
Note that we use block(X) to make sure we only talk about blocks. Let's test:
?- block_on(X, Y).
X = b,
Y = a ;
X = d,
Y = c ;
X = e,
Y = d ;
X = f,
Y = e ;
false.
Good. Now, let's define notions for being the topmost and the bottommost block on a pile:
% top(X): X is a block that is topmost on its pile
top(X) :-
block(X),
\+ block_on(_OtherBlock, X). % no other block is on X
% bottom(X): X is a block that is bottommost on its pile
bottom(X) :-
block(X),
\+ block_on(X, _OtherBlock). % X is not on any other block
This behaves like this:
?- top(X).
X = b ;
X = f.
?- bottom(X).
X = a ;
X = c ;
false.
And now we can return to your comment:
I thought something along the lines of digging deeper on both blocks till block one is paired with null, but I cant quite get my head around it.
You were talking about digging (upwards?) until you arrive at a topmost block, but in fact what you should be doing is to dig downwards until you arrive at a bottommost block! Hopefully you can see that it's easier to talk about these concepts now that we have given them clearer names, rather than descriptions like being "paired with null".
Let's start with a non-recursive rule for expressing "higher than". Any non-bottom block is definitely "higher than" any bottom block:
% higher_than(X, Y): X is a block higher on any pile than Y
higher_than(X, Y) :-
bottom(Y),
block(X),
\+ bottom(X).
This already captures a lot of relationships:
?- higher_than(X, Y).
X = b,
Y = a ;
X = d,
Y = a ;
X = e,
Y = a ;
X = f,
Y = a ;
X = b,
Y = c ;
X = d,
Y = c ;
X = e,
Y = c ;
X = f,
Y = c ;
false.
Any non-bottom block (b, d, e, f) is higher than any bottom block (a, c).
Now let's do the "digging" part to express that, for example, f is higher than b. Your idea is correct: If we're at some blocks X and Y, and X is directly on top of some block V and Y is directly on top of some block W, and we can somehow establish that V is higher than W, then X is higher than Y! Here's the same idea expressed in Prolog code:
higher_than(X, Y) :-
block_on(X, V),
block_on(Y, W),
higher_than(V, W).
So is f higher than b?
?- higher_than(f, b).
true ;
false.
Nice. And enumerating all "higher than" pairs:
?- higher_than(X, Y).
X = b,
Y = a ;
X = d,
Y = a ;
X = e,
Y = a ;
X = f,
Y = a ;
X = b,
Y = c ;
X = d,
Y = c ;
X = e,
Y = c ;
X = f,
Y = c ;
X = e,
Y = b ;
X = e,
Y = d ;
X = f,
Y = b ;
X = f,
Y = d ;
X = f,
Y = e ;
false.
Most of these are as before, but we got some new pairs as well: e is higher than b and d, f is higher than b, d, and e. And that is all!
Final remark: I'm not an expert on blocks worlds, but my impression was that it is more usual to model the table top as a special "location" rather than having a special marker for "there is nothing above this".
So I would have represented the same world more like this:
pile_on(1, a, table).
pile_on(1, b, a).
pile_on(2, c, table).
pile_on(2, d, c).
pile_on(2, e, d).
pile_on(2, f, e).
You could switch your code to this representation, maybe it would make your life easier. You could also keep the same higher_than definition -- if you adjust the definitions of block and block_on, all the rest can remain the same.
Assuming is_below( A, P, B) means block A is immediately below block B in some pile P, or is topmost in that pile, with B = null, we can code the is_higher( A, B) predicate exactly as you wanted:
we either have one more step to go down the piles and recurse, or we've reached the bottom of the B pile and judge the situation accordingly:
is_higher( A, B) :- % A is higher than B, if
is_below( A2, _, A), % A is atop one
is_below( B2, _, B), % which is _higher_ than that
A \== B, % which B is atop of
is_higher( A2, B2). % (determined _recursively_)
is_higher( A, B) :- % or,
is_below( _, _, A), % A is not bottommost
is_below( B, _, _), % while B is, because
\+ is_below( _, _, B). % there is nothing below B
%% the world: c
%% b e
%% a d
is_below(a,1,b).
is_below(b,1,c).
is_below(c,1,null).
is_below(d,2,e).
is_below(e,2,null).
Testing:
36 ?- findall( A-B, (is_higher(A,B), A\==null), X).
X = [c-b, c-e, b-a, b-d, c-a, c-d, e-a, e-d].
I am new in prolog, so i have to explain these code to my class teacher.
can someone please explain this code. Thanks
vowel(X):- member(X,[a,e,i,o,u]).
nr_vowel([],0).
nr_vowel([X|T],N):- vowel(X),nr_vowel(T,N1), N is N1+1,!.
nr_vowel([X|T],N):- nr_vowel(T,N).
output:
1 ?- nr_vowel([a,t,i,k],X).
X = 2.
https://i.stack.imgur.com/dGfU5.jpg
An explanation is indeed highly appropriate.
For example, let us ask the simplest question:
Which solutions are there at all?
Try out out, by posting the most general query where all arguments are fresh variables:
?- nr_vowel(Ls, N).
Ls = [],
N = 0 ;
Ls = [a],
N = 1.
Hm! That's probably not what you wanted to describe!
So I change your code to:
nr_vowel([], 0).
nr_vowel([X|T], N):-
vowel(X),
nr_vowel(T,N1),
N #= N1+1.
nr_vowel([X|T], N):-
nr_vowel(T,N).
Then we get:
?- nr_vowel(Ls, N).
Ls = [],
N = 0 ;
Ls = [a],
N = 1 ;
Ls = [a, a],
N = 2 ;
Ls = [a, a, a],
N = 3 ;
etc.
Looks better!
How about fair enumeration? Let's see:
?- length(Ls, _), nr_vowel(Ls, N).
Ls = [],
N = 0 ;
Ls = [a],
N = 1 ;
Ls = [e],
N = 1 ;
Ls = [i],
N = 1 ;
Ls = [o],
N = 1 ;
Ls = [u],
N = 1 ;
Ls = [_2006],
N = 0 ;
Ls = [a, a],
N = 2 ;
Ls = [a, e],
N = 2 .
The first few answers all look promising, but what about Ls = [_2006], N = 0?
This is clearly too general!
You must make your program more specific to avoid this overly general answer.
Here is the problem in a nutshell:
?- nr_vowel([X], N), X = a.
X = a,
N = 1 ;
X = a,
N = 0.
Whaaat? a is a vowel, so why is N = 0??
Here is it in a smaller nutshell:
?- nr_vowel([a], 0).
true.
Whaaaaat??
I leave adding suitable constraints to the predicate as an exercise for you.
The code is simplistic in itself, all it does is count the number of vowels in a list (Guess that's quite evident to you).
Let's take your input as an example, the list is [a,t,i,k]
When you call nr_vowel([a,t,i,k],Z), prolog searches for and unifies the query with the second nr_vowel clause, this is because it is the first clause with a non-empty list input.
Now, vowel(a) returns true, so prolog moves on to the next predicate, which calls nr_vowel([t,i,k],Z). However this time, when prolog tries to unify it with the second nr_vowel, vowel(t) returns false, so it unifies it with the third clause and behaves similarly until the list is empty.
As soon as the list is empty, prolog unifies Z with 0 and starts coming up the recursion levels and does N=N+1 depending on if the caller predicate had a vowel or not, and as soon as it reaches the top of the recursive chain, Z is unified with the final value of N.
In short -
N=N+1 happens if the head of the list is a vowel
N=N i.e. no change occurs if head of list is NOT a vowel.
Define a Prolog predicate makelist/3 such that makelist(Start, End, List) is true if
List is a list of all integers from the integer Start to the integer End. For example:
makelist(3, 7, [3, 4, 5, 6, 7]) should be true.
Can't understand why my code doesn't work
makelist(H, L, _) :-
L is H+1.
makelist(H, L, List) :-
append([], [H], List), H1 is H+1.
makelist(H1, L, List) :-
append(List, [H1], List1), last(List1, R),
R \= L+1, makelist(N, L, List1), N is H1+1.
You can simplify your code, let's take your predicate and examine what is what you really need to do:
% makelist(X,Y,L)
Since your recursive call is increasing by 1 the first parameter, let's call it X, then your base case would be when X is the same than Y:
makelist(X,X,[X]) .
and your recursive call: it will be when X is smaller than Y, you need to increase X and add the value to the list:
makelist(X,Y,[X|L]) :- X < Y ,
X1 is X + 1 ,
makelist(X1, Y, L).
I have built a predicate, which converts Roman numerals into Arabic ones. The only problem is that the predicate is limited: if I want to convert more than 3 Arabic numerals at once it does not work anymore.
This is how the predicate should work:
?- convert([v,i,i],Arabic).
Arabic = 7.
My solution so far:
tran([],0).
tran(i,1).
tran(v,5).
tran(x,10).
convert([],X) :- X is 0, !.
convert([T],X) :- tran(T,E), X is E,!.
convert([T|Ts],X) :- tran(T,E), tran(Ts,Es), X is E+Es,!.
convert([T,Ts,Tss],X) :- tran(T,E), tran(Ts,Es), tran(Tss,Ess), X is E+Es+Ess.
I know why the predicate does not work with more than 3 numerals and I could also expand the convert-predicate, but with the same pattern as shown above.
How can I make the convert-predicate more "general" (so that it could work independently of the number of numerals)? Or do you have other ideas how to write the predicate?
Thanks :)
I haven't tested this too much, but I've tried it on several numbers and it seems to work.
The code obeys "subtractive pair rule", described, for example, at https://projecteuler.net/about=roman_numerals
The code uses "accumulator" technique to pass information what was the sum of digits seen before. Initial call just sets the accumulator to 0.
digit(i, 1).
digit(v, 5).
digit(x, 10).
digit(l, 50).
digit(c, 100).
digit(d, 500).
digit(m, 1000).
convert(Roman, Arabic) :-
convert(Roman, 0, Arabic).
convert([], Acc, Acc).
convert([A], Acc, Arabic) :-
digit(A, AVal),
Arabic is Acc + AVal.
convert([A, B | Rest], Acc, Arabic) :-
digit(A, AVal), digit(B, BVal),
AVal < BVal,
NewAcc is Acc + BVal - AVal,
convert(Rest, NewAcc, Arabic).
convert([A, B | Rest], Acc, Arabic) :-
digit(A, AVal), digit(B, BVal),
AVal >= BVal,
NewAcc is Acc + AVal,
convert([B | Rest], NewAcc, Arabic).
Some tests:
convert([v, i, i], Arabic).
Arabic = 7
?- convert([x, i, x], Arabic).
Arabic = 19
?- convert([m, d, c, v, i], Arabic).
Arabic = 1606
It's probably possible to write a predicate convert that works both ways in true Prolog spirit using constraint programming, but I haven't tried this approach.
It might help if you consider the number of discrete "digits" in the Roman numbering system is more than just I, X and V, viz:
roman( "M" , 1000 ) .
roman( "CM" , 900 ) .
roman( "D" , 500 ) .
roman( "CD" , 400 ) .
roman( "C" , 100 ) .
roman( "XC" , 90 ) .
roman( "L" , 50 ) .
roman( "XL" , 40 ) .
roman( "X" , 10 ) .
roman( "IX" , 9 ) .
roman( "V" , 5 ) .
roman( "IV" , 4 ) .
roman( "I" , 1 ) .
Then you can write something like
roman_to_decimal( R , D ) :-
roman_to_decimal( R , 0 , D )
.
roman_to_decimal( [] , D , D ) :- .
roman_to_decimal( R , T , D ) :-
roman(P,V) ,
append(P,S,R) ,
! ,
T1 is T+V ,
roman_to_decimal(S,T1,D)
.
Invoke it as
roman_to_decimal( "MCM" , D ) .
This does have some shortcomings, to whit:
It doesn't enforce syntax: the Roman numbering system required the discrete components to be ordered left-to-right in descending order of value. This doesn't take that into consideration.
It doesn't take into account the many variations. Should 999 be represented as the compact IM or as the rather more verborse CMXCIX?
Just to add a variant to the mix, this version uses the scheme in Sergey's answer (which also allows more arbitrary subtractive sequences), and allows a more human-readable input like Nicholas' answer.
numeral('I', 1).
numeral('V', 5).
numeral('X', 10).
numeral('L', 50).
numeral('C', 100).
numeral('D', 100).
numeral('M', 1000).
r2n(R, N) :-
char_code(A, R),
lower_upper(A, C),
numeral(C, N).
trans(R, N) :-
maplist(r2n, R, Rn), % Pre-calculate a numeric list representation
trans(Rn, 0, N).
trans([X,Y|T], Acc, N) :-
X >= Y,
Acc1 is Acc + X,
trans([Y|T], Acc1, N).
trans([X,Y|T], Acc, N) :-
X < Y,
Acc1 is Acc - X,
trans([Y|T], Acc1, N).
trans([X], Acc, N) :-
N is Acc + X.
trans([], N, N). % Optional rule: needed only if you want trans("", 0). to succeed
Note these rules will allow any valid Roman numeral, but will also do something with and succeed on some improperly formed Roman numerals. So it is not a set of rules to validate proper Roman numerals.
Sample output:
| ?- trans("mmxiv", X).
X = 2014 ? ;
no
| ?- trans("CMXCIX", X).
X = 999 ? ;
no
| ?- trans("IM", X).
X = 999 ? ;
no
| ?- trans("IVX", X). % Not a properly-formed Roman numeral
X = 4 ? ; % Uh... ok... I guess
no
Okay, so I'm a beginner in Prolog so I'm sorry if I can't quite get my question across very clearly but this is where I'm struggling:
divide_by(X, D, I, R) :- (D > X), I is 0, R is X.
divide_by(X, D, I, R) :-
X >= D,
X_1 is X - D,
I_1 is I + 1,
divide_by(X_1, D, I_1, R),
R is X_1.
I'm trying to write a program that will accept two arguments (X and D) and return the Iterations (I) and Remainder (R) so that it can display the result of X / D when the user enters:
divide_by(8,3,I,R). for example.
When tracing the code I know that I is incorrect because the first increment makes it equal to 0 and so the count for that is wrong. But I don't know how to declare I is 0 without it resetting every time it recurses through the loop. (I don't want to declare I as 0 in the query)
I also realised that when it has finished recursing (when X < D) then I is going to be set to 0 because of the base case.
Would anyone be kind enough to show me how I can fix this?
You need to introduce an accumulator and use a helper predicate, something like this:
divide(_,0,_,_) :- !, fail . % X/0 is undefined and so can't be solved.
divide(0,_,0,0) :- !. % 0/X is always 0.
divide(X,Y,Q,R) :- % the ordinary case, simply invoke the
divrem(X,Y,0,Q,R) % helper with the accumulator seeded with 0
.
divrem(X,Y,Q,Q,X) :- % if X < Y, we're done.
X < Y . %
divrem(X,Y,T,Q,R) :- % otherwise...
X >= Y , % as long as X >= Y,
X1 is X - Y , % compute the next X
T1 is T + 1 , % increment the accumulator
divrem(X1,Y,T1,Q,R) % recurse down
. % Easy!