4

I am working on an assignment in that scans a list of numerals and should return whether the list is a valid roman numeral and the decimal value of the numerals. Ex)

1 ?- roman(N, ['I'], []).
N = 1
true.

2 ?- 

When I run the program that I feel should work, the decimal value is always right, so I'm guessing I got the synthesized attributes part right, but it always returns false for numeral lists that should return true. I'd also like to add that it aborts when it is supposed to if more than 3 Is, Xs, or Cs are present.

1 ?- roman(N, ['I'], []).
N = 1 ;
false.

2 ?- roman(N, ['I','I','I','I'], []).
Error: too many I's
% Execution Aborted
3 ?- 

When I take out the N and throw in a {write('N = '), write(N)}, it works fine and returns true.

1 ?- roman(['I'], []).
N = 1
true.

When I remove {N is ValH + ValT + ValU} it returns true, however, it no longer displays the decimal value. Here is the top line of my code (because this is a current assignment, I would prefer to show as little as is necessary to get an answer):

roman(N) --> hundreds(ValH), tens(ValT), units(ValU), {N is ValH + ValT + ValU}.

Why is this returning false with N, but true without, and how do I fix it?

Assignment: The following BNF specification defines the language of Roman numerals less than 1000:

<roman> ::= <hundreds> <tens> <units>
<hundreds> ::= <low hundreds> | CD | D <low hundreds> | CM
<low hundreds> ::= e | <low hundreds> C
<tens> ::= <low tens> | XL | L <low tens> | XC
<low tens> ::= e | <low tens> X
<units> ::= <low units> | IV | V <low units> | IX
<low units> ::= e | <low units> I

Define attributes for this grammar to carry out two tasks:

a) Restrict the number of X’s in <low tens>, the I’s in <low units>, and the C’s in <low hundreds> to no more than three.

b) Provide an attribute for <roman> that gives the decimal value of the Roman numeral being defined.

Define any other attributes needed for these tasks, but do not change the BNF grammar.

false
  • 10,264
  • 13
  • 101
  • 209
Ross Verry
  • 115
  • 8
  • 1
    use phrase/2 to 'call' a DCG grammar – CapelliC Feb 15 '13 at 15:36
  • I think you must pay strict attention to detail. See [this answer](http://stackoverflow.com/a/13269846/874024) for a nice alternative schema. – CapelliC Feb 15 '13 at 15:53
  • I have to stick strictly to the BNF. I can post that if you like. – Ross Verry Feb 15 '13 at 16:04
  • By adding a cut it now says `N = 1.` and no true or false. My professor uses an older version and he posted a screenshot of what our results should be. I just thought about this, and I doubt it is the case, but could it be that the older version says `N = 1 /n Yes.` and the new version just doesn't output the true? – Ross Verry Feb 15 '13 at 20:38
  • SWI-Prolog doesn't show uninstantiated variables at top level, while the display of false (after a ';') means that there was some choice point left, but the engine couldn't dispose of them. You should concentrate on completing your assignment, and I suggest to ignore those details. Avoid the cut, should be useless. – CapelliC Feb 15 '13 at 23:15

1 Answers1

2

Did you noticed the grammar is formed of the same pattern (group//5) repeated 3 times, just with different symbols ? I like the compactness...

roman(N) -->
    group('C','D','M',100, H),
    group('X','L','C',10, T),
    group('I','V','X',1, U),
    {N is H+T+U}.
group(A,B,C, Scale, Value) -->
    (   g3(A, T)
    ;   [A, B], {T = 4}
    % thanks to Daniel and Will for catching bugs
    ;   [B], g3(A, F), {T is 5+F}
    ;   [B], {T is 5}
    ;   [A, C], {T = 9}
    ;   {T = 0}
    ),  {Value is Scale * T}.


g3(C, 1) --> [C].
g3(C, 2) --> [C,C].
g3(C, 3) --> [C,C,C].

some test

?- atom_chars('CMXXX',L), phrase(roman(N),L).
L = ['C', 'M', 'X', 'X', 'X'],
N = 930 ;
false.

?- atom_chars('CMXLVIII',L), phrase(roman(N),L).
L = ['C', 'M', 'X', 'L', 'V', 'I', 'I', 'I'],
N = 943 ;
false.

Just a curiousity, showing DCG at work...

edit after Daniel and Will comments...

?- atom_chars('VIII',L), phrase(roman(N),L).
L = ['V', 'I', 'I', 'I'],
N = 8 .

?- phrase(roman(X), ['L','I','X']).
X = 59 .
CapelliC
  • 59,646
  • 5
  • 47
  • 90