有三个朋友 - 米莎,彼佳,沃瓦。 姓氏:伊万诺夫、谢苗诺夫、格拉西莫夫。
name(misha).
name(vova).
name(petya).
surname(ivanov).
surname(semyonov).
surname(gerasimov).
米沙不是格拉西莫夫。
full_name(misha,X) :-
surname(X),
X = gerasimov.
沃瓦在六年级学习。 格拉西莫夫在五年级。 如何定义 vova 的姓氏(几个(?
沃瓦的父亲是工程师,伊万诺夫的父亲是锁匠。
father(vova,ingeneer).
father(ivanov,locksmith).
如何定义沃瓦的姓氏(一个(?
首先,我们需要捕捉每个名字都有一个给定姓氏的事实。
is_one_of(Name, [ivanov, semyonov, gerasimov]) :-
member(Name, [misha, vova, petya]).
我们还被赋予了关于名字和姓氏的特征(学习,父亲(,每个都有不同的价值观。这由以下谓词捕获。
name_characteristic(vova, studying, sixth_grade).
name_characteristic(vova, father, ingeneer).
surname_characteristic(gerasimov, studying, fifth_grade).
surname_characteristic(ivanov, father, locksmith).
我们也得到了gerasimov
is_not
姓氏misha
.
is_not(misha, gerasimov).
规则 1:Name
不能Surname
某些共同特征的值是否不同。
is_not(Name, Surname) :-
name_characteristic(Name, Characteristic, Value1),
surname_characteristic(Surname, Characteristic, Value2),
Value1 = Value2.
规则2:如果其他可能的姓氏都不是Name
姓氏,则必须Name
Surname
。
is_(Name, Surname) :-
is_one_of(Name, Surnames),
select(Surname, Surnames, RemainingSurnames),
is_none_of(Name, RemainingSurnames).
is_none_of(_, []).
is_none_of(Name, [Surname | RemainingSurnames]) :-
is_not(Name, Surname),
is_none_of(Name, RemainingSurnames).
查询is(vova, Surname)
收益:
Surname = semyonov
查询is_not(Name, Surname)
收益:
Name = misha,
Surname = gerasimov
Name = vova,
Surname = gerasimov
Name = vova,
Surname = ivanov
这个解决方案使用chr
库,它实际上是一种与Prolog略有不同的语言。我现在自己正在学习CHR,这实际上是我用它编写的第二个程序。它可能与我在邮件列表中获得的改进版本过于相似。所以用一粒盐来服用。
在我看来,CHR非常适合那些从很多可能性开始然后抵消坏可能性的程序。也许取消可以继续,直到您收敛到解决方案。这就是这个程序的工作方式,我们生成所有可能的名字/姓氏集,然后使用不可能约束来减少可能的姓氏集,直到它们收敛到一个,然后我们从其他名字/姓氏集中删除它们,直到一切都收敛。
前两行介绍了库和我们将使用的约束:
:- use_module(library(chr)).
:- chr_constraint name/1, surnames/1, impossible/2, matched/2, possible/2.
第一个约束产生了我们需要克服的可能性。
gen_possibilities @
name(Name), surnames(Surnames)
==> possible(Name, Surnames).
这里的想法是,我们已经在一个列表中有了姓氏,我们只是在每个名字和所有可能的姓氏之间制作一对名为possible
的姓氏。
impossibility @
impossible(Name, Surname), possible(Name, Surnames)
<=> select(Surname, Surnames, Remaining)
| possible(Name, Remaining).
一旦我们被告知某件事是不可能的,我们可以简单地将其从该名称的可能姓氏列表中删除。select/3
对于从列表中删除单个项目并为您提供其余部分非常有用。我们在这里使用一个守卫,以防姓氏已经不在可能的姓氏列表中,就像应用第四个约束后可能发生的那样。
only_possiblity @
possible(Name, [Surname])
<=> matched(Name, Surname).
一旦可能性列表减少到一个名字,我们就成功地进行了匹配。
remove_matched @
matched(_, Surname), possible(Name, _)
==> impossible(Name, Surname).
如果我们进行了匹配,那么对于所有其他名字来说,这个姓氏就变得不可能了。
如果由于名称已处理而无法吸收不可能约束,则可以添加额外的清理约束,但不是必需的:
irrelevant_impossibility @
possible(Name, Surnames)
impossible(Name, Surname)
<=> + memberchk(Surname, Surnames)
| true.
现在我们可以运行该程序了。我冒昧地为 5 年级/6 年级和不同的父亲内联逻辑。我觉得通过阅读很容易理解意图,我认为通过专门建模不会获得太多好处。@RobertBaron为他的解决方案带来麻烦而致敬!
main :-
name(misha),
name(vova),
name(petya),
surnames([ivanov, semyonov, gerasimov]),
impossible(misha, gerasimov), % stated impossible
impossible(vova, gerasimov), % different grades
impossible(vova, ivanov). % different fathers
执行此操作的结果是:
?- main.
name(petya),
name(vova),
name(misha),
surnames([ivanov, semyonov, gerasimov]),
matched(petya, gerasimov),
matched(misha, ivanov),
matched(vova, semyonov).
我相信这满足了摆在你们面前的限制。