i have this code that converts integers into roman numerals
i need to add a function that compares an integer with a roman numeral input and show if it's try or false, for example:
roman(v,5).
true
toroman(0).
toroman(N) :- N < 4, put("I"), M is N - 1, toroman(M).
toroman(N) :- N = 4, put("I"), put("V").
toroman(N) :- N = 5, put("V").
toroman(N) :- N < 9, put("V"), M is N - 5, toroman(M).
toroman(N) :- N = 9, put("I"), put("X").
toroman(N) :- N < 40, put("X"), M is N - 10, toroman(M).
toroman(N) :- N < 50, put("X"), put("L"), M is N - 40, toroman(M).
toroman(N) :- N < 90, put("L"), M is N - 50, toroman(M).
toroman(N) :- N < 100, put("X"), put("C"), M is N - 90, toroman(M).
toroman(N) :- N < 400, put("C"), M is N - 100, toroman(M).
toroman(N) :- N < 500, put("C"), put("D"), M is N - 400, toroman(M).
toroman(N) :- N < 900, put("D"), put("D"), M is N - 500, toroman(M).
toroman(N) :- N < 1000, put("C"), put("M"), M is N - 900, toroman(M).
toroman(N) :- N < 4000, put("M"), M is N - 1000, toroman(M).
roman(N) :- toroman(N).
Try to formulate the problem differently: Write a grammar (dcg) to relate an integer and a list of characters denoting roman numerals. Here is a start:
:- use_module(library(clpfd)).
roman(0) --> "".
roman(N0) --> "I", { 1 #=< N0, N0 #=< 3, N1 #= N0-1}, roman(N1).
You can use it like so:
?- phrase(roman(3), L).
L = "III" ;
false.
or
?- phrase(roman(N), "II").
N = 2 ;
false.
or, if you don't know what to ask, simply ask the most general question:
?- phrase(roman(N), L).
N = 0,
L = [] ;
N = 1,
L = "I" ;
N = 2,
L = "II" ;
N = 3,
L = "III" ;
false.
To get answers compactly like L = "III"
, use :- set_prolog_flag(double_quotes,chars).
See this answer for more.
You should change your toroman/1
procedure to something like toroman/2
that returns the roman numeral instead of just printing it.
Then you would be able to easily compare a roman numeral with the result from calling toroman/2
to the integer.
Note also that your current procedure will loop until getting a stack overflow if you backtrack for another solution. You should either guard each clause that recursively calls itself to recurse only if the parameter of the call is non-negative or add as the first clause a check that fails safely, e.g.:
roman(N):- N < 0, !, fail.
After changing toroman/1 to return the roman literal you would get something like this (just modified a bit your code to return the literal as the second argument):
toroman(N, _):- N < 0, !, fail.
toroman(0, []).
toroman(N, ['I'|Roman]) :- N < 4, M is N - 1, toroman(M, Roman).
toroman(4, ['IV']).
toroman(5, ['V']).
toroman(N, ['V'|Roman]) :- N < 9, M is N - 5, toroman(M, Roman).
toroman(9, ['IX']).
toroman(N, ['X'|Roman]) :- N < 40, M is N - 10, toroman(M, Roman).
toroman(N, ['XL'|Roman]) :- N < 50, M is N - 40, toroman(M, Roman).
toroman(N, ['L'|Roman]) :- N < 90, M is N - 50, toroman(M, Roman).
toroman(N, ['XC'|Roman]) :- N < 100, M is N - 90, toroman(M, Roman).
toroman(N, ['C'|Roman]) :- N < 400, M is N - 100, toroman(M, Roman).
toroman(N, ['CD'|Roman]) :- N < 500, M is N - 400, toroman(M, Roman).
toroman(N, ['DD'|Roman]) :- N < 900, M is N - 500, toroman(M, Roman).
toroman(N, ['CM'|Roman]) :- N < 1000, M is N - 900, toroman(M, Roman).
toroman(N, ['M'|Roman]) :- N < 4000, M is N - 1000, toroman(M, Roman).
roman(N, R) :- toroman(N, L), atomic_list_concat(L, R).
roman(N) :- roman(N, R), write(R).
Then you could simply call roman(N, R)
and test whether R
unifies with your roman numeral of interest.