这是事实:
address(host1, '10.0.0.1').
address(host2, '10.0.0.2').
Run Code Online (Sandbox Code Playgroud)
我可以查询一个事实:
?- address(host1, X).
X = '10.0.0.1'.
Run Code Online (Sandbox Code Playgroud)
我是Prolog的新手,但我习惯了关系数据库.在SQL数据库中,我对数据进行约束以防止错误.如果我想确保所有地址都在A类网络10.0.0.0/8中,我可以对表列进行约束:
create table hosts (
name text,
address text check (address like '10.%')
);
Run Code Online (Sandbox Code Playgroud)
我如何在Prolog中做同样的事情来防止错误的事实?
您撰写的事实等同于以下规则:
address(host1, '10.0.0.1') :- true. address(host2, '10.0.0.2') :- true.
true/0是最普遍的目标:它总是成功的.
要更强烈地约束条款,您可以添加更多目标.在Prolog中,每个目标都是对答案的约束.
@coder的回答是:你可以简单地编写规则来添加这些检查,它们与数据库约束相似(并且比表达更具表现力).
例如,你可以写:
host_ip(host1, IP) :- IP = '10.0.0.1', good_ip(IP). host_ip(host2, IP) :- IP = '10.0.0.2', good_ip(IP).
注意谓词命名约定:为了弄清楚每个参数是什么,我使用的host_ip/2不是简单的address/2.
可能的定义good_ip/1是:
good_ip(IP) :- atom_concat('10.', _, IP).
如果iff IP开始,这是真的10..
此时,问题是您是否选择了最合适的IP地址表示!
如果您经常需要分析组件,请考虑例如表示:
ip(A,B,C,D)
在这个表示中,我们可以写:
host_ip(host1, IP) :- IP = ip(10,0,0,1), good_ip(IP). host_ip(host2, IP) :- IP = ip(10,0,0,2), good_ip(IP). good_ip(ip(10,_,_,_)).
编辑:正如您在评论中正确指出的那样,这只能防止提取错误的IP,而不是断言或添加错误的事实或条款.
为了使后者成为可能,请考虑@lurker概述的方法:您可以简单地定义如下规则:
add_host_ip(Host, IP) :-
good_ip(IP),
assertz(host_ip(Host,IP)).
这可以防止您向数据库添加错误的IP,假设您始终使用此接口谓词.
另请注意,如果给出了错误的IP,则将其与抛出异常相结合.例如:
good_ip(ip(First,_,_,_)) :-
dif(First, 10),
throw(wrong_subnet(First)).
good_ip(ip(10,_,_,_)).
示例会话:
?- add_host_ip(host3, ip(11,0,0,0)). ERROR: Unhandled exception: wrong_subnet(11) ?- add_host_ip(host4, ip(10,0,0,1)). true. ?- host_ip(host3, IP). false. ?- host_ip(host4, IP). IP = ip(10, 0, 0, 1).
这说明无效的IP现在既不存储也不作为答案返回.