您是否注意到语法是由重复 3 次的相同模式 (group//5) 组成,只是使用不同的符号?我喜欢紧凑的...
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].
一些测试
?- 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.
只是出于好奇,展示 DCG 的工作情况......
edit在丹尼尔和威尔评论之后……
?- atom_chars('VIII',L), phrase(roman(N),L).
L = ['V', 'I', 'I', 'I'],
N = 8 .
?- phrase(roman(X), ['L','I','X']).
X = 59 .