假设我有这些DCG:
zorbs([H|T]) --> zorb(H), zorbs(T).
zorbs([]) --> [].
zorb(a) --> [1,2].
zorb(b) --> [3].
zorb(c) --> [6,1,2,2].
我可以做到:
?- phrase(zorbs(X), [1,2,3,6,1,2,2]).
X = [a, b, c] .
我也可以";反向";这样做:
phrase(zorbs([a,b,c]), X).
X = [1, 2, 3, 6, 1, 2, 2].
现在,我想做的是找到一个长度小于4的数字列表(例如(;解析";进入,返回其余部分。
因此,例如,给定[a,b,c]
,它通常与[1, 2, 3, 6, 1, 2, 2]
相关,我希望它与[1, 2, 3]
(其长度小于4(相关,并给出不可能是"0"的余数;反转,";因此CCD_ 4。我真的不知道从哪里开始,因为似乎没有办法对DCG中已经消耗的元素数量进行推理。
这里有一种解决方案:
X in 0..4,
indomain(X),
Q = [_|_],
prefix(Q, [a,b,c]),
length(A, X),
phrase(zorbs(Q), A).
但我认为这是非常低效的,因为我认为它基本上是从无到有的迭代,我想找到具有最大Q
的解决方案。
在这种情况下没有直接的方法。所以你的方法本质上是可以做的。也就是说,您列举了所有可能的解决方案,并相应地选择了它们(您没有显示(。
关于最大等的问题包括一些量化,你不能直接用一阶逻辑表达。
然而,有时你可以使用一些技巧。
有时,类似[a,b,c|_]
的部分列表可能会有所帮助。
?- Xs = [_,_,_,_|_], phrase(zorbs(Xs),[1,2,3,6,1,2,2]).
false.
因此,在这里我们已经证明,没有长度为4或更长的列表对应于该序列。也就是说,我们已经为无限多的列表证明了这一点!
有时,使用phrase/3
代替phrase/2
可能会有所帮助。比方说,你有一个不解析的数字序列,你想知道它能解析多远:
?- Ys0 = [1,2,3,6,1,2,7], phrase(zorbs(Xs),Ys0,Ys).
Ys0 = [1,2,3,6,1,2,7], Xs = [], Ys = [1,2,3,6,1,2,7]
; Ys0 = [1,2,3,6,1,2,7], Xs = "a", Ys = [3,6,1,2,7]
; Ys0 = [1,2,3,6,1,2,7], Xs = "ab", Ys = [6,1,2,7]
; false.
(这是交换了两个DCG规则(
可以使用:
% Like "between", but counts down instead of up
count_down(High, Low, N) :-
integer(High),
integer(Low),
count_down_(High, Low, N).
count_down_(H, L, N) :-
compare(C, H, L),
count_down_comp_(C, H, L, N).
count_down_comp_('=', _H, L, N) :-
% All equal, final
N = L.
% Accept H as the counting-down value
count_down_comp_('>', H, _L, H).
count_down_comp_('>', H, L, N) :-
H0 is H - 1,
% Decrement H towards L, and loop
count_down_(H0, L, N).
然后从开始
count_down(4, 1, Len), length(Lst, Len), phrase...
另一种方法是使用freeze
逐元素限制列表的长度:
max_len_freeze(Lst, MaxLen) :-
compare(C, MaxLen, 0),
max_len_freeze_comp_(C, Lst, MaxLen).
max_len_freeze_comp_('=', [], 0).
max_len_freeze_comp_('>', [_|Lst], MaxLen) :-
succ(MaxLen0, MaxLen),
!,
freeze(Lst, max_len_freeze(Lst, MaxLen0)).
max_len_freeze_comp_('>', [], _).
然后从开始
max_len_freeze(Lst, 4), phrase...
这将首先找到最长的列表(最大长度4(,因为您的DCG是贪婪(即在[]
之前匹配[H|T]
(。