You give the testcase ?- caesar("hello",L2).
which can be handled in several ways.
Since SWI 7 the default are strings. But this is not a common encoding. For other encodings
see this.
The most straight forward and traditional method is.
:- set_prolog_flag(double_quotes,codes).
After putting this directive into your file, or issuing on the toplevel:
?- set_prolog_flag(double_quotes,codes).
true.
?- L = "hello".
L = [104,101,108,108,111].
Now, the method to encode can be directly applied. Julius Caesar used the method a bit differently from what you have indicated. In particular did he use modulo, and sometimes different offsets. Also, ASCII was unknown to him, only capital letters, no digits (only like XVII). Permit me to include the new fangled letters G (C with cauda), J (I with cauda), U (fancy V), W (fancy VV). Otherwise we would need an explicit table.
Here is the general cypher relation using library(clpfd)
. 0'A
is the character code of A, 0'Z
that of Z.
:- use_module(library(clpfd)).
cypher(Code, A,B) :-
[A,B] ins 0'A..0'Z, % only letters!
B #= 0'A+((A-0'A)+Code)mod 26.
Note that this is a relation ; it can be used to encode:
?- cypher(1, 0'A, Y).
Y = 0'B.
... and also to decode:
?- cypher(1, X, 0'B).
X = 0'A.
So finally we can apply this relation to lists of codes:
?- maplist(cypher(1),"ABC",L), atom_codes(A, L).
L = [66,67,68], A = 'BCD'.
?- maplist(cypher(1),"ABC","BCD").
true.
?- maplist(cypher(1),X,"BCD"), atom_codes(A, X).
X = [65,66,67], A = 'ABC'.
Pretty annoying to always be forced to convert the integers back into something readable. Isn't it? Well, there is a better approach:
:- set_prolog_flag(double_quotes, chars).
Another method is to use chars, they have the big advantage that answer are now much more readable, but with library(double_quotes)
they are perfectly readable. Simple download it.
?- set_prolog_flag(double_quotes, chars).
true.
?- L = "ABC".
L = ['A','B','C'].
?- use_module(double_quotes).
true.
?- L = "ABC", L = [C|Cs].
L = "ABC", C = 'A', Cs = "BC".
However, our cypher-relation get's now more complex, as we have to convert characters to codes:
xcypher(Code, ACh, BCh) :-
( nonvar(ACh) -> char_code(ACh, A) ; char_code(BCh, B) ),
cypher(Code, A, B),
char_code(ACh, A),
char_code(BCh, B).
And this is how Caesar read about it (proof):
?- maplist(xcypher(1),Xs, "SPNBOFTFWOUEPNWT").
Xs = "ROMANESEVNTDOMVS".