Prolog Roman Numerals (Attribute Grammars) - prolog

I am working on an assignment in prolog 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.

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 .

Related

Prolog: How to generate simple math expressions?

I need to write (not calculate) all the states of list of number that means :
Input:
Numbers: 1,2,3
Operators: +,-,/,*
Output:
1+2+3
1-2-3
1/2/3
1*2*3
1+2-3
1+2/3
1+2*3
1-2+3
1-2/3
1-2*3
1/2+3
1/2-3
1/2+3
1*2+3
1*2-3
1+2-3
in descend code just show 1+2+3
How can I develop them to all states?
list_sum([Item], Item).
list_sum([Item1,Item2 | Tail], Total) :-
list_sum([Item1+Item2|Tail], Total).
A variation of the nice solution posted by Carlo Capelli allows us to illustrate an useful programming idiom to better exploit first-argument indexing:
list_combine([N1| Ns], Os, Nt) :-
list_combine(Ns, N1, Os, Nt).
list_combine([], N, _, [N]).
list_combine([N2| Ns], N1, Os, [N1, O| Nt]) :-
member(O, Os),
list_combine(Ns, N2, Os, Nt).
The idea is to pass the list we want to walk by separating the list head from the tail and pass both as argument with the tail as first argument, as exemplified above.
In the original solution, the Prolog compiler will generally not distinguish between a list with just one element and a list with one or more elements. But it will distinguish between an empty list (an atom) and a list with at least one element (a compound term). Note also that the original version creates a spurious choice-point, for each recursive call, on the call to the list_combine/3 predicate in addition to the intended choice-point on the member/2 predicate call.
a simple recursion:
list_combine([N|Nr],Os,[N,O|Nt]) :-
member(O,Os),
list_combine(Nr,Os,Nt).
list_combine([N],_,[N]).
and now
?- forall(list_combine([1,2,3],[+,*],C),writeln(C)).
[1,+,2,+,3]
[1,+,2,*,3]
[1,*,2,+,3]
[1,*,2,*,3]
true.
here is a - maybe - more readable version
list_combine(Ns,Os,Cs) :-
[N|Nr] = Ns,
member(O,Os),
Cs = [N,O|Nt],
list_combine(Nr,Os,Nt).
Of course, use in alternative, just to better understand how unification acts in decomposing and composing arguments.
Using DCG with phrase/2 as a generator:
operator --> [+].
operator --> [-].
operator --> [*].
operator --> [/].
expr_trinary -->
[1],
operator,
[2],
operator,
[3].
expr(E) :-
phrase(expr_trinary,Expr_trinary),
atomics_to_string(Expr_trinary,E).
Example run:
?- expr(E).
E = "1+2+3" ;
E = "1+2-3" ;
E = "1+2*3" ;
E = "1+2/3" ;
E = "1-2+3" ;
E = "1-2-3" ;
E = "1-2*3" ;
E = "1-2/3" ;
E = "1*2+3" ;
E = "1*2-3" ;
E = "1*2*3" ;
E = "1*2/3" ;
E = "1/2+3" ;
E = "1/2-3" ;
E = "1/2*3" ;
E = "1/2/3".
Since your question works with list, a way to see DCG as list processing is to use listing/1 to convert it to regular Prolog.
?- listing(operator).
operator([+|A], A).
operator([-|A], A).
operator([*|A], A).
operator([/|A], A).
true.
?- listing(expr_trinary).
expr_trinary([1|A], B) :-
operator(A, C),
C=[2|D],
operator(D, E),
E=[3|B].
true.
which can be called as regular Prolog.
?- expr_trinary(E,[]).
E = [1, +, 2, +, 3] ;
E = [1, +, 2, -, 3] ;
E = [1, +, 2, *, 3] ;
E = [1, +, 2, /, 3] ;
E = [1, -, 2, +, 3] ;
E = [1, -, 2, -, 3] ;
E = [1, -, 2, *, 3] ;
E = [1, -, 2, /, 3] ;
E = [1, *, 2, +, 3] ;
E = [1, *, 2, -, 3] ;
E = [1, *, 2, *, 3] ;
E = [1, *, 2, /, 3] ;
E = [1, /, 2, +, 3] ;
E = [1, /, 2, -, 3] ;
E = [1, /, 2, *, 3] ;
E = [1, /, 2, /, 3].
An expanded solution using a number (1,2,3) in any position:
number --> [1].
number --> [2].
number --> [3].
operator --> [+].
operator --> [-].
operator --> [*].
operator --> [/].
expr_trinary -->
number,
operator,
number,
operator,
number.
expr(E) :-
phrase(expr_trinary,Expr_trinary),
atomics_to_string(Expr_trinary,E).
Example run:
?- expr(E).
E = "1+1+1" ;
E = "1+1+2" ;
E = "1+1+3" ;
E = "1+1-1" ;
E = "1+1-2" ;
E = "1+1-3" ;
...
For a explanation of how to generate with DCG see this Amzi section: Generating with Difference Lists
In comment for other answer you wrote:
its not work more than 3 element? can you develop it for more elements?
As the number of elements increases so does the combinatorial explosion.
To keep the combinatorial explosion down for the example run this will only use two numbers (1,2) and two operators (+,*), you can add more to your liking.
number(1) --> [1].
number(2) --> [2].
operator(+) --> [+].
operator(*) --> [*].
expr(N) --> number(N).
expr((E1,Op,E2)) --> operator(Op),expr(E1),expr(E2).
expr(E) :-
length(Expr,_),
phrase(expr(E),Expr).
Note that this uses length/2 for iterative deepening. Basically length/2 generates list of increasing length and then phrase/2 comes up with answers that are of that length.
?- length(Ls,N).
Ls = [],
N = 0 ;
Ls = [_870],
N = 1 ;
Ls = [_870, _876],
N = 2 ;
Ls = [_870, _876, _882],
N = 3 ;
Ls = [_870, _876, _882, _888],
N = 4 ;
Ls = [_870, _876, _882, _888, _894],
N = 5 ;
Ls = [_870, _876, _882, _888, _894, _900],
N = 6
...
So that generator works as expected the normal BNF and DCG, e.g.
<expr> ::= <expr> <op> <expr>
expr((E1,Op,E2)) --> expr(E1),operator(Op),expr(E2).
which is direct left recursive is converted to this
<expr> ::= <op> <expr> <expr>
expr((E1,Op,E2)) --> operator(Op),expr(E1),expr(E2).
Example run:
?- expr(E).
E = 1 ;
E = 2 ;
E = (1, (+), 1) ;
E = (1, (+), 2) ;
E = (2, (+), 1) ;
E = (2, (+), 2) ;
E = (1, (*), 1) ;
E = (1, (*), 2) ;
E = (2, (*), 1) ;
E = (2, (*), 2) ;
E = (1, (+), 1, (+), 1) ;
...
E = (1, (+), 2, (+), 2, (*), 1) ;
E = (1, (+), 2, (+), 2, (*), 2) ;
E = (1, (+), (1, (+), 1), (+), 1) ;
E = (1, (+), (1, (+), 1), (+), 2) ;
E = (1, (+), (1, (+), 2), (+), 1) ;
...
One way is
get_calcul([X], _, Temp, Calcul):-
append(Temp, [X], Calcul).
get_calcul([N|T], [Op|Top], Temp, Out) :-
append(Temp, [N, Op], Temp1),
get_calcul(T, Top, Temp1, Out).
all_operations(In, Out) :-
setof(Op, X^Ops^(permutation([+,-,*,/], X), get_calcul(In, X, [], Ops), atomic_list_concat(Ops, Op)), Out).
Result
?- all_operations([1,2,3], Out).
Out = ['1*2+3', '1*2-3', '1*2/3', '1+2*3', '1+2-3', '1+2/3', '1-2*3', '1-2+3', '1-2/3'|...].
Well, I solved my problem, not your's !
This can be done :
member_(In, X) :-
member(X, In).
get_calcul([N], _, Temp, Out) :-
append(Temp, [N], Out).
get_calcul([N|T], [Op|Top], Temp, Out) :-
append(Temp, [N, Op], Temp1),
get_calcul(T, Top, Temp1, Out).
all_operations(In, Out) :-
% if you have N numbers
length(In, Len),
% you need N-1 operators
LenOps is Len - 1,
length(LOps, LenOps),
setof(Op, LOps^Ops^(maplist(member_([+,-,*,/]), LOps),get_calcul(In, LOps, [], Ops), atomic_list_concat(Ops, Op)), Out).
For example :
?- all_operations([1,2,3], Out), maplist(writeln, Out).
1*2*3
1*2+3
1*2-3
1*2/3
1+2*3
1+2+3
1+2-3
1+2/3
1-2*3
1-2+3
1-2-3
1-2/3
1/2*3
1/2+3
1/2-3
1/2/3
Out = ['1*2*3', '1*2+3', '1*2-3', '1*2/3', '1+2*3', '1+2+3', '1+2-3', '1+2/3', '1-2*3'|...].
This my solution proposal, which I find to be very simple and straight forward, copy and paste below to notepad++ editor to get best readability.
* ________________________________________________ *
*|find_expression(NumsList,TargetValue,Expression)| *
**------------------------------------------------* *
* Expression is an arithmetic expression of the numbers in Numslist with *
* possible operators '+','-','*','/' and '(' and ')' between the numbers *
* in such a way that the expression evaluates to the TargetValue argument *
*****************************************************************************/%
/* a single element number list can evaluate only to itself */
find_expression([SingleNumber],SingleNumber,SingleNumber).
/* expression of a multypile number list */
find_expression(NumberList,Target,Expression):-
/* non-deterministically divide the number list
into 2 separate lists which include at least one number each*/
append([X|Xs],[Y|Ys], NumberList),
/* recursively find an expression for east list,
where the expression evaluates to itself */
find_expression([X|Xs],Exp1,Exp1),
find_expression([Y|Ys],Exp2,Exp2),
/* non-deterministically choose an operand from [+,-,*,division]
and compose Expression to be (Exp1 Operand Exp2) */
( member(Expression,[Exp1+Exp2,Exp1-Exp2,Exp1*Exp2])
; /* prevent zero divison */
(Val2 is Exp2, Val2 =\= 0, Expression = (Exp1/Exp2))), %/*
/* assure that final expression evaluates(matches) the target value
and convert value from integer to float if necessary */
( Target = Expression ; Target is Expression
; FloatTarget is Target*1.0, FloatTarget is Expression).

Checking if a string is contained in a language (Prolog)

This is the CFG:
S -> T | V
T -> UU
U -> aUb | ab
V -> aVb | aWb
W -> bWa | ba
so this will accept some form of:
{a^n b^n a^m b^m | n,m >= 1} U {a^n b^m a^m b^n | n,m >= 1}
And here is the code I'm working with:
in_lang([]).
in_lang(L) :-
mapS(L), !.
mapS(L) :-
mapT(L) ; mapV(L),!.
mapT(L) :-
append(L1, mapU(L), L), mapU(L1), !.
mapU([a|T]) :-
((append(L1,[b],T), mapU(L1)) ; (T = b)),!.
mapV([a|T]) :-
((append(L1,[b],T), mapV(L1)) ;
(append(L1,[b],T), mapW(L1))),
!.
mapW([b|T]) :-
((append(L1,[a],T), mapW(L1)) ;
(T = a)),
!.
As of right now, this is returning false for the following three strings:
[a,a,b,b,a,b] // this should be true
[a,a,a,b,b,a,a,b,b,b] // this should be true as well
[a,a,a,b,b,a,b,b,b] // this one IS false
Any help or insight would be greatly appreciated, I'm not too comfortable with Prolog so debugging this by myself has been a challenge.
Simply use a dcg! And library(double_quotes).
:- set_prolog_flag(double_quotes, chars).
s --> t | v.
t --> u, u.
u --> "a",u,"b" | "ab".
v --> "a",v,"b" | "a",w,"b".
w --> "b",w,"a" | "ba".
?- use_module(library(double_quotes)).
?- length(L,N), phrase(s, L).
L = "abab", N = 4
; L = "abab", N = 4
; L = "aabbab", N = 6
; L = "abaabb", N = 6
; L = "aababb", N = 6
; L = "abbaab", N = 6
; L = "aaabbbab", N = 8
; L = "aabbaabb", N = 8
; L = "abaaabbb", N = 8
; L = "aaababbb", N = 8
; ... .
First, note that this code doesn't make sense:
... append(L1, mapU(L), L) ...
In Prolog there are predicates, not functions...
A CFG production rule (a non terminal) should 'eat' a number of tokens, and in Prolog this means you need at least 2 arguments: the input token list, and what remains after a production has successfully matched the relevant part of input.
That is, append/3 is not required: just pattern matching, performed by unification operator (=)/2
mapS(L1, L) :- mapT(L1,L) ; mapV(L1,L).
mapT(L1, L) :- mapU(L1,L2), mapU(L2,L).
mapU(L1, L) :- L1=[a|L2], mapU(L2,L3), L3=[b|L] ; L1=[a,b|L].
... complete the translation
and then call it:
?- mapS([a,a,b,b,a,b],R).
R = [] ;
false.
R = [] means the entire sequence has been matched...
In the definition of mapT, you are trying to use the "return value" of mapU as an argument to append. But mapU is a predicate, and predicates don't have return values.
Instead one typically writes a predicate with an unbound variable which the predicate binds to the desired "return value"; after the predciate has been proven, the now bound variable can be used in subsequent predicates.

Prolog - summing up predicate results

Let's say i have the following predicate:
func1(X,B,R)
I provide it with a certain X and B and in return it gives me 5 different results for R.
EDIT:
The X and B do not specify a range. rather, X specify an integer (say 120) and B specifies all integers (starting from 1) whose cubic is less than X.
What func1 does is calculating R as the result the remainder.
In this case where X=120:
B = 1, R = 119 (120-1^3)
B = 2, R = 112 (120-2^3)
B = 3, R = 93 (120-3^3)
B = 4, R = 56 (120-4^3)
It would not calculate B=5 since 5^3 = 125 which is greater than 120, so it stops here.
How can i make a predicate such as:
func2(R,S)
That would accept all of the results given by R, sum them up and store them in S?
Thanks!
To start with, since the values of B are totally derivable from the value of X, I wouldn't include both as arguments in func1. I'll introduce a predicate func3/2 which is true if the second argument is derivable from the first (i.e., func3(X, B) is true if B is derivable from X):
func1(X, R) :-
func3(X, B),
...
What will happen if you query func1(120, R) is you'd get one or more results for R. Then you can use findall/3 as I indicated in my comment:
func2(X, S) :-
findall(R, func1(X, R), Rs),
sumlist(Rs, S).
To define func3/2 the cleanest approach would be to use CLP(FD):
:- use_module(library(clpfd)).
func3(X, B) :-
B #>= 0,
(X - B^3) #>= 0,
label([B]).
Here's an example of what func3 does:
?- func3(120, B).
B = 1 ;
B = 2 ;
B = 3 ;
B = 4.
A much less desirable way to do this if you can't use CLP(FD) would be to use between and define the upper limit of B to be the greatest integer not exceeding the cube root of X:
func3(X, B) :-
Limit is floor(exp(log(X) / 3)),
between(1, Limit, B).
Which yields the same result as above.

Prolog: append number to a term

Is it possible to append a number to a term directly?
I.e., I can easily do something like this:
?- A = 1 + 2, B = 3, C = A + B.
C = 1+2+3
But is there a way (operator?) to specify something instead of '+' in the C = A + B to get "C = 1+23"?
I feel I'm asking for something strange, so here is the context. I have a list of digits, and I want to generate all expressions that can be obtained by putting '+', '-' or nothing between the digits.
Pluses and minuses are easy part:
possible([X], X) :- !.
possible([A, B | Rest], E) :-
( H = A + B ; H = A - B ),
possible([H | Rest], E).
?- possible([1, 2, 3], E).
E = 1+2+3 ?;
E = 1+2-3 ?;
E = 1-2+3 ?;
E = 1-2-3
yes
But I also want to get "E = 12+3", "E = 1+23" and "E = 123". Is there an easy way to do it?
Update: the solution should be portable or at least work in B-Prolog.
here is my bet
possible([N|Ns], D) :-
digits_number([N|Ns], D).
possible([N|Ns], X) :-
append([L|Ls], [R|Rs], [N|Ns]),
possible([L|Ls], Lx),
digits_number([R|Rs], Rx),
(Op = + ; Op = -), X =.. [Op, Lx, Rx].
digits_number(Digits, N) :-
maplist(digit_code, Digits, Codes),
number_codes(N, Codes).
digit_code(D, C) :-
C is D + 0'0.
The purpose of the verbose [N|Ns], etc is to avoid matching empty lists.
edit Here is a variation, that doesn't require maplist/3 and number_codes/2. The code it's quite similar in size...
possible(Ns, D) :-
digits_number(Ns, _, D).
possible([N|Ns], X) :-
append([L|Ls], [R|Rs], [N|Ns]),
possible([L|Ls], Lx),
digits_number([R|Rs], _, Rx),
(Op = + ; Op = -), X =.. [Op, Lx,Rx].
digits_number([Digit], 1, Digit).
digits_number([D|Ds], F, N) :-
digits_number(Ds, G, T),
F is G * 10,
N is T + D * F.
It's more efficient tough (at least on inference count), indeed here is a performance test
?- L=[1,2,3,4,5,6,7,8], time(findall(X,possible_1(L,X),L1)), time(findall(X,possible_2(L,X),L2)).
% 31,591 inferences, 0.017 CPU in 0.017 seconds (100% CPU, 1851600 Lips)
% 20,656 inferences, 0.017 CPU in 0.018 seconds (98% CPU, 1192235 Lips)
L = [1, 2, 3, 4, 5, 6, 7, 8],
L1 = L2, L2 = [12345678, 1+2345678, 1-2345678, 12+345678, 12-345678, 1+2+345678, 1+2-345678, ... - ... + 345678, ... - ...|...].
Of course, I've renamed the two versions possible_1, possible_2
How about this simple and fully portable solution:
possible([Digit], Digit).
possible([Digit| Digits], Digit + RightExpression) :-
possible(Digits, RightExpression).
possible([Digit| Digits], Digit - RightExpression) :-
possible(Digits, RightExpression).
possible([Digit1, Digit2| Digits], Expression) :-
Number0 is Digit1 * 10,
Number is Number0 + Digit2,
possible([Number| Digits], Expression).
Using B-Prolog for testing:
$ bp
B-Prolog Version 8.1, All rights reserved, (C) Afany Software 1994-2014.
| ?- [possible].
consulting::possible.pl
yes
| ?- possible([1,2,3], Exp).
Exp = 1+(2+3) ?;
Exp = 1+(2-3) ?;
Exp = 1+23 ?;
Exp = 1-(2+3) ?;
Exp = 1-(2-3) ?;
Exp = 1-23 ?;
Exp = 12+3 ?;
Exp = 12-3 ?;
Exp = 123 ?;
no
Regarding performance, using the same benchmark as in Carlo's answer, I get:
?- L=[1,2,3,4,5,6,7,8], time(findall(X,possible(L,X),L1)).
% 12,037 inferences, 0.003 CPU in 0.003 seconds (93% CPU, 4223509 Lips)
L = [1, 2, 3, 4, 5, 6, 7, 8],
L1 = [1+ (2+ (3+ (4+ (5+ (6+ (7+8)))))), 1+ (2+ (3+ (4+ (5+ (6+ (7-8)))))), 1+ (2+ (3+ (4+ (5+ (6+78))))), 1+ (2+ (3+ (4+ (5+ (... - ...))))), 1+ (2+ (3+ (4+ (... + ...)))), 1+ (2+ (3+ (... + ...))), 1+ (2+ (... + ...)), 1+ (... + ...), ... + ...|...].
This solution works without string-to-term conversions. It still depends on the SWI-Prolog predicate atom_number/2 (not sure how widely available this is). If ISO compliance is necessary, I believe it should suffice to write a custom atom_number/2 predicate using atom_codes/2 and number_codes/2. digit_appended_to_expression/3 is actually too general, since it will work with any predicate that takes a number as its second argument.
digit_appended_to_expression(Expression, C, ExpressionWithC) :-
Expression =.. [Operator, A, B],
digit_concat(B, C, BC),
ExpressionWithC =.. [Operator, A, BC].
digit_concat(A, B, AB) :-
number(A),
number(B),
atom_number(A_Atom, A),
atom_number(B_Atom, B),
atom_concat(A_Atom, B_Atom, AB_Atom),
atom_number(AB_Atom, AB).
possible([X], X) :- !.
possible([A, B | Rest], E) :-
( digit_concat(A, B, H)
; H = A + B
; H = A - B
; digit_appended_to_expression(A, B, H)
),
possible([H | Rest], E).
This still doesn't give an operator, because it needs a 3-place predicate, but one could use term expansion to achieve macro if it were really important.
Is it sufficient?
Here is a possible (pun intended) solution using accumulators:
%numberexp( D, N, XN) :- number_chars( D, DL), DL=[ DC| _], number_chars( N, NL), number_chars( XN, [ DC| NL]).
numberexp( D, N, XN) :- XN is integer( exp( log( 10)*(1+integer( log( 10, N))))*D+N).
poss( [ H], H, Z, Z).
poss( [ H| T], H, Z, E) :- poss( T, F, F, XT), E= Z+XT.
poss( [ H| T], H, Z, E) :- poss( T, F, F, XT), E= Z-XT.
poss( [ H| T], A, Z, E) :- poss( T, F, Z, E), numberexp( H, F, A).
possible( L, E) :- poss( L, F, F, E).
The number expansion part is admittedly ugly either ways, but at least it can be portably ugly.
The output is:
| ?- possible([1,2,3],E).
E = 1+(2+3) ?;
E = 1+(2-3) ?;
E = 1+23 ?;
E = 1-(2+3) ?;
E = 1-(2-3) ?;
E = 1-23 ?;
E = 12+3 ?;
E = 12-3 ?;
E = 123 ?;
no
I initially misunderstood your question and just approached it as a list processing exercise using DCGs. I only realized that you were trying to generate Prolog terms after I'd finished with the DCG. But I was able to get a workable solution by converting the list to a string and then the string to a term using SWI-Prolog's string handling predicates. I'd be interested to know of a more straightforward way of accomplishing this.
possible(Digits, AsTerm) :-
phrase(sequence(Digits), Sequence),
atomics_to_string(Sequence, AsString),
term_string(AsTerm, AsString).
sequence(Ds) -->
digits(Ds).
sequence(Ds) --> {append(First, Last, Ds)},
digits(First), sign, sequence(Last).
digits([D]) -->
digit(D).
digits([D|Ds]) -->
digit(D), digits(Ds).
digit(D) --> {integer(D)},
[D].
sign --> [+].
sign --> [-].
This version of possible/2 will generate evaluable prolog terms:
?- possible([1,2,3],X), Y is X.
X = Y, Y = 123 ;
X = 1+23,
Y = 24 ;
X = 1+2+3,
Y = 6 ;
X = 1+2-3,
Y = 0 ;
...

Sicstus Prolog - Weight of a word

I've got a problem about how to weigh a word.
Every single letter in a word has specific weight, I need to calculate the total weight of the word.
For example:
A-E = 1, F-O = 2, P-Z = 3.
If the word is "PEN", the answer will be "Weight = 6",
cuz P = 3, E = 1 and N = 2.
I've tried:
word_weight([X], W):-
X = 65 -> W = 1;
X = 66 -> W = 3.
word_weight([X,Y],W):-
X = 65 -> W1 = 1;
X = 66 -> W1 = 3,
Y = 65 -> W2 = 1;
Y = 66 -> W2 = 3,
W is W1 + W2.
word_weight([X|Y], W):-
X = 65 -> W = 1;
X = 66 -> W = 3,
word_weight(Y, W).
Running res:
| ?- word_weight("B",W).
W = 3 ?
yes
It only works with one letter. How to make it works with many letters? And the answers will be the total value of the weight.
The following program works with SWI-Prolog. It will be surely easy to adapt it to Sicstus Prolog.
char_weight(C, 1) :- C >= 65, C =< 69.
char_weight(C, 2) :- C >= 70, C =< 79.
char_weight(C, 3) :- C >= 80, C =< 90.
word_weight([], 0).
word_weight([Char| Chars], Weight) :-
char_weight(Char, W),
word_weight(Chars, Ws),
Weight is W + Ws.
How about
weight(C, 1) :- char_code('A') =< C, C =< char_code('E').
weight(C, 2) :- char_code('F') =< C, C =< char_code('O').
weight(C, 3) :- char_code('P') =< C, C =< char_code('Z').
word_weight(S, W) :- string(S), !, string_list(S, L), word_weight(L, W).
word_weight([], 0).
word_weight([H|T], W) :- W is weight(H) + word_weight(T).
in ECLiPSe-CLP, string_list/2 converts a string into a list of numberic character codes, char_code/2 gets the numeric code of a character.
Edit:
Oops, I should have read your question completely:
Wen using ->/2, you should use brackets and don't hesitate to use indentation:
( Condition ->
IfBranch
;
ElseBranch
),
RestProg.
Your second clause is a bit unreadable. But for this excercise you shouldn't need ->/2 at all.
Your third clause only works for a single-letter string, because it first unifies W with the value for X and then wants to unify W with the weight of X. This only works if Y and X have the same weight.

Resources