如何将列表与数据库Prolog进行比较



我有一个事实数据库,其中包含类似此片段的条目

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统一,并在反向链接时传回。通常变量会被命名为Symptoms0Symptoms但我以这种方式保留它们,以便它们更容易遵循。其他明智的是,会有变量SymptomSymptomsSymptoms0,但是一旦你习惯了它们就更容易遵循了。

重复项的检查是使用 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].

相关内容

  • 没有找到相关文章

最新更新