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

时间:2019-02-15 20:11:29

标签: list prolog compare

我有一个事实数据库,其中包含这样的片段

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]
    ).

我的问题是如何将用户症状列表与第二个原子事实症状进行比较,然后将该疾病添加到另一个列表中? 例如,用户输入发烧。由于发烧是带状疱疹的症状,因此会将带状疱疹添加到清单中。

1 个答案:

答案 0 :(得分:1)

这将起作用,但是允许输入重复的症状。我现在将其发布,以便您可以看到转换的第一部分,并且当我开始工作时将发布没有重复的部分。

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) 

如果症状无效,则向用户提供反馈format/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]一起添加到列表中,并且两个分支(真和假)都应更新相同的变量Symptoms,在假变量中分支是通过Symptoms = Symptoms0完成的,valid_symptom/2不是分配,而是=/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统一,并在反向链接时返回。通常,这些变量将分别命名为SymptomsSymptom,但我将其保留为这种方式,以便于跟踪。否则,会有变量SymptomsSymptoms0?- 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]. ,但是一旦习惯了它们,就更容易理解了。

使用memberchk/2进行重复检查比使用member/2进行检查要好。再次,这为混合添加了另一个条件。

示例运行:

import sys
exe = sys.executable