Dan*_*ons 5 prolog expression-evaluation
假设我有一些看起来像的表达式a /\ b \/ c
.我想为此生成真值表,例如:
a | b | c | a /\ b \/ c
---+----+----+-------------+-
F | F | F | F
F | F | T | T
F | T | F | F
F | T | T | T
T | F | F | F
T | F | T | T
T | T | F | T
T | T | T | T
Run Code Online (Sandbox Code Playgroud)
这里的一个关键思想是处理尚未处理的运算符is/2
,例如逻辑含义->
.顺便说一句,这个问题来自reddit用户u/emergenthoughts 的帖子.
我的代码如下:
bool(0).
bool(1).
negate(1, 0).
negate(0, 1).
eval(Assignments, A, V) :- atom(A), memberchk(A=V, Assignments).
eval(Assignments, \+ E, V) :- eval(Assignments, E, NotV), negate(NotV, V).
eval(Assignments, E1 /\ E2, V) :-
eval(Assignments, E1, V1),
eval(Assignments, E2, V2),
V is V1 /\ V2.
eval(Assignments, E1 \/ E2, V) :-
eval(Assignments, E1, V1),
eval(Assignments, E2, V2),
V is V1 \/ V2.
eval(Assignments, E1 -> E2, V) :-
eval(Assignments, E1, V1),
V1 = 1 -> eval(Assignments, E2, V) ; V = 1.
generate_assignment(Variable, Variable=B) :- bool(B).
generate_assignments(Variables, Assignments) :-
maplist(generate_assignment, Variables, Assignments).
atoms_of_expr(A, A) :- atom(A).
atoms_of_expr(\+ E, A) :- atoms_of_expr(E, A).
atoms_of_expr(E1 /\ E2, A) :- atoms_of_expr(E1, A) ; atoms_of_expr(E2, A).
atoms_of_expr(E1 \/ E2, A) :- atoms_of_expr(E1, A) ; atoms_of_expr(E2, A).
atoms_of_expr(E1 -> E2, A) :- atoms_of_expr(E1, A) ; atoms_of_expr(E2, A).
table_for(E) :-
setof(A, atoms_of_expr(E, A), Variables),
write_header(Variables, E),
write_separator(Variables, E),
table_rest(Variables, E).
table_rest(Variables, E) :-
generate_assignments(Variables, Assignments),
eval(Assignments, E, Value),
write_assignments(Assignments, Value),
fail.
table_rest(_, _) :- true.
write_header([Var|Rest], E) :-
write(' '), write(Var), write(' | '), write_header(Rest, E).
write_header([], E) :- writeln(E).
write_separator([_|R], E) :- write('---+-'), write_separator(R, E).
write_separator([], _) :- write('-+-'), nl.
write_assignments([_=Var|Rest], Value) :-
write(' '), write(Var), write(' | '), write_assignments(Rest, Value).
write_assignments([], Value) :- writeln(Value).
Run Code Online (Sandbox Code Playgroud)
这段代码产生的输出略差,但我不想让你厌烦大量的格式:
?- table_for(a/\b\/c).
a | b | c | a/\b\/c
---+----+----+--+-
0 | 0 | 0 | 0
0 | 0 | 1 | 1
0 | 1 | 0 | 0
0 | 1 | 1 | 1
1 | 0 | 0 | 0
1 | 0 | 1 | 1
1 | 1 | 0 | 1
1 | 1 | 1 | 1
true.
Run Code Online (Sandbox Code Playgroud)
我相信这个解决方案相当简单,而且我喜欢它,但是我真的很惊讶Prolog是真正的向导能够做到的,所以我想我会问这里是否有重大改进.atoms_of_expr/2
感觉有点像样板,因为它复制了遍历eval/3
.我没有看到使用的方法,term_variables/2
因为我不认为我能够实际提供变量具有的名称或正确绑定它们memberchk/2
.我错了吗?
小智 1
嗯,我不确定我是否理解这个问题和评论,但也许我可以做出一些贡献。我非常非常抱歉:这不是我写的代码,但我记得我第一次在学校某个地方做逻辑时发现了它,我真的很抱歉,但我不记得在哪里找到它。我也稍微改变了一下,因为在我发现它之前它并不是很好。但是,如果有人认识此代码,请告诉我,我会将其记下或归因于代码的真正作者。
这是我的代码。我神秘地命名它lc.pl
,因为 2 个字母只多于 1 个字母,但比任何其他数字都少。我不知道“c”是什么意思。“l”表示我希望的逻辑。
:- module(lc, [
bl/2,
valid/1,
contradiction/1,
lequiv/2,
truth_table/2,
op(100, fy, ?),
op(200, fy, ~),
op(500, yfx, and),
op(500, yfx, or),
op(690, yfx, =>),
op(700, yfx, <=>)]).
truth_table(F, T) :-
term_variables(F, Vs),
bagof(R-Vs, bl(F, R), T).
valid(F) :-
forall(bl(F, R), R == t).
contradiction(F) :-
forall(bl(F, R), R == f).
lequiv(F, G) :-
forall(( bl(F, X), bl(G, Y) ), X == Y).
bl(?X, R) :-
v(X, R).
bl(~X, R) :-
bl(X, R0),
not(R0, R).
bl(X and Y, R) :-
bl(X, R0),
and_bl(R0, Y, R).
bl(X or Y, R) :-
bl(X, R0),
or_bl(R0, Y, R).
bl(X => Y, R) :-
bl(X, R0),
impl_bl(R0, Y, R).
bl(X <=> Y, R) :-
bl(X, R0),
bl(Y, R1),
eq(R0, R1, R).
bl(X xor Y, R) :-
bl(X, R0),
bl(Y, R1),
xor(R0, R1, R).
v(f, f).
v(t, t).
not(t, f).
not(f, t).
and_bl(f, _, f).
and_bl(t, Y, R) :- bl(Y, R).
or_bl(f, Y, R) :- bl(Y, R).
or_bl(t, _, t).
impl_bl(t, Y, R) :- bl(Y, R).
impl_bl(f, _, t).
eq(f, Y, R) :- not(Y, R).
eq(t, Y, Y).
xor(f, Y, Y).
xor(t, Y, R) :- not(Y, R).
Run Code Online (Sandbox Code Playgroud)
抱歉代码很长:-(
你看到了term_variables/2
,但你没有看到atoms_of_expr
,因为它没有使用原子,因为当变量更容易使用时为什么要使用原子呢?我不知道。
无论如何,这是我记得如何将它用于与您的示例相同的示例,但以非常不同的方式编写:
?- truth_table(?A and ?B or ?C, Table).
Table = [f-[f, _3722, f], t-[f, _3692, t], f-[t, f, f], t-[t, f, t], t-[t, t, _3608]].
Run Code Online (Sandbox Code Playgroud)
所以显然没有自述文件,但如果你想要“布尔变量”而不是“逻辑变量”,你需要写一个?在前面使其成为“布尔值”。为什么 ?我不知道。经过多次尝试和错误,我发现我必须写?在变量之前使其成为布尔值;很多代码如果忘记写就不会终止?变量前面:-(
但它在运算符列表中具有含义和等价性。您会看到解决方案中的真值表非常不同,但实际上是相同的。