So I'm really interested in Erlang. I can't find an excuse to use it for anything big, but I try to use it for toy problems from time to time.
Right now, I'm implementing a Roman Numeral translator. I'm just doing the "to" part for now, and I'm finding the code is awfully repetitive. It works like a charm, but, well, just look at it:
-module(roman).
-compile([export_all]).
toRoman(N) ->
toRoman(N, []).
toRoman(0,Acc) ->
lists:reverse(lists:flatten(Acc));
toRoman(N, Acc) when N >= 1000 ->
toRoman(N-1000,["M"|Acc]);
toRoman(N,Acc) when N >= 900 ->
toRoman(N-900,["CM" | Acc]);
toRoman(N,Acc) when N >= 500 ->
toRoman(N-500,["D" | Acc]);
toRoman(N,Acc) when N >= 400 ->
toRoman(N-400, ["CD" | Acc]);
toRoman(N,Acc) when N >= 100 ->
toRoman(N-100, ["C" | Acc]);
toRoman(N,Acc) when N >= 90 ->
toRoman(N-90, ["XC" | Acc]);
toRoman(N,Acc) when N >= 50 ->
toRoman(N-50, ["L" | Acc]);
toRoman(N, Acc) when N >= 40 ->
toRoman(N-40, ["XL" | Acc]);
toRoman(N, Acc) when N >= 10 ->
toRoman(N-10, ["X" | Acc]);
toRoman(N, Acc) when N >= 9 ->
toRoman(N-9, ["IX" | Acc]);
toRoman(N, Acc) when N >= 5 ->
toRoman(N-5, ["V" | Acc]);
toRoman(N, Acc) when N >= 4 ->
toRoman(N-4, ["IV" | Acc]);
toRoman(N, Acc) ->
toRoman(N-1, ["I" | Acc]).
test() ->
Test = fun(X) -> io:format("~p -> ~p~n", [X, toRoman(X)]) end,
lists:map(Test, [0,1,3,6,23,43,75,87,13,23, 3999, 3998, 2531, 140]).
I feel like there's a much better way to do this. Can anyone provide some insight?
Actually your code isn't that repetitive. It just looks like it because the text forms a repetitive pattern. But each of your clauses handles a specific case with little logical overlap between them. You could reimplement in a switch statement but you would get a similar repetition. There are just too many cases in a roman numeral translation and I don't think you will be able to avoid the repetitive feel making each of those individual decisions causes.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With