如何编写Prolog规则实现receives_twice(C,A):验证客户恰好2笔达标转账
如何实现Prolog规则验证客户恰好收到两笔达标转账?
背景说明
已在Prolog程序中定义以下关系:
account(B, C, N):B为银行名称,C为客户,N为账号;transactions(N1, N2, A, D):N1为转出账号,N2为转入账号,A为转账金额,D为转账日期。
需求
需编写规则receives_twice(C, A),验证客户C恰好收到两笔金额均不小于A的转账。现有规则仅能验证存在达标转账,无法满足“恰好两笔”的要求。
给定的Prolog事实及不完整规则
account(reiffeisen, max, "0"). account(privat24, john, "1"). account(reiffeisen, olivia, "2"). account(privat24, jack, "3"). account(monobank, linda, "4"). account(monobank, omen, "5"). account(privat24, johnny, "6"). account(reiffeisen, historia, "7"). account(reiffeisen, clark, "8"). account(monobank, victor, "9"). transactions("0", "1", 100, "05"). transactions("1", "4", 200, "10"). transactions("1", "8", 500, "12"). transactions("9", "7", 100, "06"). transactions("5", "3", 5000, "08"). transactions("6", "9", 10, "01"). transactions("8", "7", 50, "02"). transactions("9", "0", 1200, "04"). transactions("5", "1", 800, "03"). transactions("3", "0", 1000, "07"). transactions("1", "6", 1400, "04"). transactions("6", "1", 2000, "05"). transactions("3", "1", 2500, "05"). transactions("1", "1", 2800, "05"). receives_twice(C, A) :- account(_, C, Q), transactions(_, Q, M, _), M >= A.
修改方案
有两种简洁的实现方式,都能满足“恰好两笔达标转账”的验证要求:
方式一:通过否定目标排除第三笔转账
receives_twice(C, A) :- % 关联客户C与对应的账号Q account(_, C, Q), % 匹配第一笔金额达标(>=A)的转账,记录其日期D1(用日期区分不同转账) transactions(_, Q, M1, D1), M1 >= A, % 匹配第二笔金额达标且与第一笔不同的转账(日期不同) transactions(_, Q, M2, D2), M2 >= A, D1 \= D2, % 否定存在第三笔达标且日期不重复的转账 \+ (transactions(_, Q, M3, D3), M3 >= A, D3 \= D1, D3 \= D2).
方式二:用findall统计达标转账数量
这种写法更直观,通过收集所有达标转账并检查数量实现:
receives_twice(C, A) :- account(_, C, Q), % 收集所有金额>=A的转账日期到列表Ts中 findall(D, (transactions(_, Q, M, D), M >= A), Ts), % 验证列表长度恰好为2,即恰好两笔达标转账 length(Ts, 2).
逻辑说明
- 方式一通过匹配两笔不同的达标转账,再用否定目标确保没有第三笔,实现“恰好两笔”的约束;
- 方式二利用
findall把所有达标转账的标识(这里用日期)收集成列表,直接检查列表长度是否为2,代码更简洁易读。
比如测试客户historia,当A=50时,他的达标转账有两笔(金额50和100),此时receives_twice(historia, 50)会返回true。
内容的提问来源于stack exchange,提问作者PrologMaster
相关产品推荐
相关产品推荐

