我有一个事实数据库,其中包含类似此片段的条目
symptom(shingles,headache).
symptom(shingles,fever).
symptom(shingles,malaise).
symptom(shingles,headache).
symptom(shingles,itching).
symptom(shingles,hyperesthesia).
symptom(shingles,paresthesia).
test(shingles,blood).
test(shingles,pcr).
locale(shingles,all).
treatment(shingles,calamine).
treatment(shingles,aciclovir).
treatment(shingles,valaciclovir).
treatment(shingles,famciclovir).
treatment(shingles,corticosteroids).
然后,我有一个谓词,可以从用户那里获取症状列表。
getSymptoms(Symptoms) :-
write('Please enter symptoms now, enter "Done" when finished: ' ),
read_string(user, "n", "r", _, Response),
(
Response == "Done"
->
Symptoms = []
;
getSymptoms(Symptoms0),
Symptoms = [Response|Symptoms0]
).
我的问题是如何将用户症状列表与症状事实第二个原子进行比较,然后将疾病添加到另一个列表中? 例如,用户进入发烧状态。由于发烧是带状疱疹的症状事实,因此会将带状疱疹添加到列表中。
这将起作用,但允许输入重复的症状。我现在发布它,以便您可以看到转换的第一部分,并在我开始工作时发布没有重复的部分。
getSymptoms(Symptoms) :-
write('Please enter symptoms now, enter "Done" when finished: ' ),
read_string(user, "n", "r", _, Response),
(
Response == "Done"
->
Symptoms = []
;
atom_string(Symptom,Response),
valid_symptom(Symptom,Symptoms)
).
valid_symptom(Symptom,Symptoms) :-
(
symptom(_,Symptom)
->
% Symptom was valid
% so get next symptom and
% add to list on backtracking
getSymptoms(Symptoms0),
Symptoms = [Symptom|Symptoms0]
;
% Symptom was invalid
% so warn user of invalid symptom and what they input
% and get next symptom.
% Do not add invalid Symptom to list on backtracking.
format('Invalid symptom: `~w''~n',[Symptom]),
getSymptoms(Symptoms0),
Symptoms = Symptoms0
).
由于输入的值是字符串,而症状是symptom/2
事实中的原子,因此需要将输入转换为原子进行比较。这是使用 atom_string/2 完成
atom_string(Symptom,Response)
在症状无效时向用户提供反馈 格式/2 使用。它比 write/1 更好使用,因为它可以让您更好地控制输出。
format('Invalid symptom: `~w''~n',[Symptom])
如果输入了无效值作为症状,则不应将其添加到列表中。这是一个经典的 if/then 类型的场景,在 Prolog 中是用 ->/2 完成的。这是标准模板
(
<conditional>
->
<true branch>
;
<false branch>
)
条件是
symptom(_,Symptom)
还要注意条件,它读取symptom/2
事实并忽略复合结构的第一部分,即_
,并将输入症状与事实中的症状匹配。这是完成的比较,但它是通过统一而不是使用比较谓词(例如 ==/2)完成的。
真正的分支和以前一样
getSymptoms(Symptoms0),
Symptoms = [Symptom|Symptoms0]
然而,错误的分支是
format('Invalid symptom: `~w''~n',[Symptom]),
getSymptoms(Symptoms0),
Symptoms = Symptoms0
请注意,无效的Symptom
不会添加到带有[Symptom|Symptoms0]
的列表中,并且两个分支(true 和 false)都应该更新相同的变量,Symptoms
,这在 false 分支中是用Symptoms = Symptoms0
完成的,这不是赋值而是 =/2(统一)。
valid_symptom/2
的代码本可以用getSymptoms/1
内联,但我把它拉出来,这样你就可以看到它是如何完成的,以防你将来需要这样做。
示例运行:
?- getSymptoms(Symptoms).
Please enter symptoms now, enter "Done" when finished: wrong
Invalid symptom: `wrong'
Please enter symptoms now, enter "Done" when finished: headache
Please enter symptoms now, enter "Done" when finished: malaise
Please enter symptoms now, enter "Done" when finished: headache
Please enter symptoms now, enter "Done" when finished: Done
Symptoms = [headache, malaise, headache].
这是在构建列表时删除重复项的下一个变体。
getSymptoms(Result) :-
getSymptoms_helper([],Result).
getSymptoms_helper(Symptoms,Result) :-
write('Please enter symptoms now, enter "Done" when finished: ' ),
read_string(user, "n", "r", _, Response),
(
Response == "Done"
->
Result = Symptoms
;
atom_string(Symptom,Response),
valid_symptom(Symptom,Symptoms,Result)
).
valid_symptom(Symptom,Symptoms,Result) :-
(
memberchk(Symptom,Symptoms)
->
% Symptom was a duplicate
% Do not add duplicate Symptom to list.
getSymptoms_helper(Symptoms,Result)
;
(
symptom(_,Symptom)
->
% Symptom was valid
% so get next symptom and
% add to list.
getSymptoms_helper([Symptom|Symptoms],Result)
;
% Symptom was invalid
% so warn user of invalid symptom and what they input
% and get next symptom.
% Do not add invalid Symptom to list.
format('Invalid symptom: `~w''~n',[Symptom]),
getSymptoms_helper(Symptoms,Result)
)
).
此处的主要更改是累加器Symptoms
通过谓词进行线程处理,以便可以构建有效症状列表并用于测试下一个输入值。由于累加器需要在开始时初始化,因此将之前的谓词重命名为getSymptoms_helper
,以便累加器可以初始化
getSymptoms_helper([],Result)
[]
注意传递给
getSymptoms_helper(Symptoms,Result)
从而将Symptoms
的初始值设置为[]
。
输入Done
时,列表与Result
统一,并在反向链接时传回。通常变量会被命名为Symptoms0
和Symptoms
但我以这种方式保留它们,以便它们更容易遵循。其他明智的是,会有变量Symptom
、Symptoms
和Symptoms0
,但是一旦你习惯了它们就更容易遵循了。
重复项的检查是使用 memberchk/2 完成的,这比使用 member/2 进行检查要好。这再次为组合添加了另一个条件。
示例运行:
?- getSymptoms(Symptoms).
Please enter symptoms now, enter "Done" when finished: headache
Please enter symptoms now, enter "Done" when finished: malaise
Please enter symptoms now, enter "Done" when finished: headache
Please enter symptoms now, enter "Done" when finished: Done
Symptoms = [malaise, headache].