Problem 89 「ローマ数字」 †

ローマ数字は同じ数をあらわすのに色々な表記ができる。
ファイルに必ずしも最短の長さでない方法で書かれたローマ数字が1000個書かれている。
これを最短の長さに置き換えた場合何文字節約できるか答えよ。
ファイルや詳細はリンク先参照のこと。


解法
データファイルを文字列を集めたリストに手作業で変換し。
それを読み込み、文字コードリストを文字のリストに変換。
文字のリスト各文字を10進数字に変換して、10進数字からそのローマ数字の表す10進数時に
変換し、10進数時を最短のローマ数字で表記した時の長さを計算してとコードを書いた。

一つ一つの手順はおかしくないし丁寧に掛けたのだが何か冗長すぎる気がしてならない。
もうちょっと色々な部分をショートカットできるような気はする。


to_num('I',1):-!.
to_num('V',5):-!.
to_num('X',10):-!.
to_num('L',50):-!.
to_num('C',100):-!.
to_num('D',500):-!.
to_num('M',1000):-!.

char_Nums([],[]):-!.
char_Nums([C|Char],[N|Result]):-
	char_code(C1,C),
	to_num(C1,N),
	char_Nums(Char,Result).


to_char([],[]):-!.
to_char([Row|Rows],[Row1|Result]):-
	!,
	to_char(Rows,Result),
	char_Nums(Row,Row1).

sum_lens([],0):-!.
sum_lens([X|Xs],Result):-
	!,
	sum_lens(Xs,Re),
	length(X,Len),
	Result is Re+Len.

change_num([],Add,_,Sum,Result):-!,Result is Add+Sum.
change_num([X|Rest],Add,X,Sum,Result):-
	!,
	Add1 is Add+X,
	change_num(Rest,Add1,X,Sum,Result).
change_num([X|Rest],Add,Old,Sum,Result):-
	X<Old,
	!,
	Sum1 is Sum+Add,
	change_num(Rest,X,X,Sum1,Result).
change_num([X|Rest],Add,_,Sum,Result):-
	!,
	Sum1 is Sum-Add,
	change_num(Rest,X,X,Sum1,Result).

change_nums([],[]):-!.
change_nums([R|Rows],[Re|Result]):-
	!,
	[Top|Rest]=R,
	change_num(Rest,Top,Top,0,Re),
	change_nums(Rows,Result).


to_len(X,2):-member(X,[2,4,6,9]),!.
to_len(X,X1):-member(X,[5,7,8]),!,X1 is X-4.
to_len(X,X1):-!,X1 is X.

calc_len([],0):-!.
calc_len([X|Xs],Result):-calc_len(Xs,Re),
	to_len(X,Add),
	Result is Re+Add.

roman_Len(Num,Result):-
	!,
	A1 is Num//1000,
	A2 is (Num mod 1000)//100,
	A3 is (Num mod 100) // 10,
	A4 is (Num mod 10),
	calc_len([A2,A3,A4],Len),
	Result is Len+A1.
sum_roman_len([],0):-!.
sum_roman_len([R|Rows],Result):-
	!,
	roman_Len(R,Len),
	sum_roman_len(Rows,Re),
	Result is Re+Len.


main89:-
	open('pe89.txt',read,IS),
	read_term(IS,Rows,[]),
	close(IS),
 	sum_lens(Rows,Ans1),
	to_char(Rows,Rows1),
	change_nums(Rows1,Rows2),
	sum_roman_len(Rows2,Ans2),
	Ans3 is Ans1-Ans2,
	write([ans,Ans3]).