Using seq//1 https://stackoverflow.com/a/24106828/772868:
list_splitonstop(Xs, As, Bs) :-
phrase( ( seq(As), [stop], seq(Bs) ), Xs).
该版本按您的预期工作:
?- L = [tea,coffee,sugar,cake,stop,meat,fish,eggs,flour],
list_splitonstop(L, L1, L2).
L = [tea,coffee,sugar,cake,stop,meat,fish,eggs,flour],
L1 = [tea,coffee,sugar,cake], L2 = [meat,fish,eggs,flour]
; false.
但是,这真的是最好的解决方案吗?这; false
最后可能表明事实并非如此。但我们不能肯定地说这一点。我们必须找出该解决方案无法按预期工作的另一种情况。在其他编程语言中,您也面临类似的问题,必须很大程度上依赖程序员的想象力来找出边界情况等。
幸运的是,我们在这里使用 Prolog,它可以帮助我们理解我们实际定义的内容。
一个非常简单的第一步是询问最一般的查询。就像那样:
?- list_splitonstop(L, L1, L2).
L = [stop], L1 = [], L2 = []
; L = [stop,_A], L1 = [], L2 = [_A]
; L = [stop,_A,_B], L1 = [], L2 = [_A,_B]
; L = [stop,_A,_B,_C], L1 = [], L2 = [_A,_B,_C]
; ... .
看看每个答案!我们以第三个为例。L = [stop,_A,_B]
意味着这个答案包括all包含三个元素的列表,其中第一个元素是stop
。所以我们在这里寻找一个infinity解决方案都已用几个字符进行了紧凑的描述!甚至不bzip2 -99
可以做到这一点!
这些是唯一包含三个元素的列表吗?我们不能仅从这个单一的查询中说出这一点,因为 Prolog 可能会在一个unfair方式。想象一下,你要求某人告诉你所有的自然数,但那个人从 0, 2, 4, ... 开始,显然,这种枚举对奇数非常不公平。同样,有些答案可能会丢失......
在 Prolog 中,我们可以坚持只查看长度为 3 的列表:
?- L = [_,_,_], list_splitonstop(L, L1, L2).
L = [stop,_A,_B], L1 = [], L2 = [_A,_B]
; L = [_A,stop,_B], L1 = [_A], L2 = [_B]
; L = [_A,_B,stop], L1 = [_A,_B], L2 = []
; false.
因此,我们可以在单个查询中询问长度为 3 的所有相关案例。请注意,这些_A
and _B
变量代表任何术语!请花点时间欣赏您正在查看的内容:长度为 3 的列表的所有案例。没有其他案例需要考虑!
当您查看这些答案时,可能会出现一些问题。就像:这三个答案是否重叠,或者它们真的是脱节的? Prolog 知道答案。只需重复实际目标并计算结果答案:
?- L = [_,_,_], list_splitonstop(L, L1, L2), list_splitonstop(L, L1, L2).
(answers same as above)
所以我们得到了完全相同的答案。不存在固有的冗余。
另一个问题可能是:L
总是恰好有一种可能的分裂? (换句话说:是否存在函数依赖性?)
我们可以通过询问来实现这一点L
具有不同的L1
and L2
:
?- L = [_,_,_], dif(L1-L2,L1x-L2x),
list_splitonstop(L, L1, L2), list_splitonstop(L, L1x, L2x).
L = [stop,stop,_A], L1 = [], L2 = [stop,_A], L1x = [stop], L2x = [_A]
; L = [stop,_A,stop], L1 = [], L2 = [_A,stop], L1x = [stop,_A], L2x = []
; L = [stop,stop,_A], L1 = [stop], L2 = [_A], L1x = [], L2x = [stop,_A]
; L = [_A,stop,stop], L1 = [_A], L2 = [stop], L1x = [_A,stop], L2x = []
; L = [stop,_A,stop], L1 = [stop,_A], L2 = [], L1x = [], L2x = [_A,stop]
; L = [_A,stop,stop], L1 = [_A,stop], L2 = [], L1x = [_A], L2x = [stop]
; false.
那么,我现在可以问你:你想要上面的案例吗?如果出现多次stop
?显然,您没有具体说明这一点,我们需要您提供更多信息。 Prolog 至少有助于识别此类情况。
如何识别冗余答案。
在上面的例子中,我们观察到没有多余的答案。但当他们出现的时候,他们又是如何出现的呢?这是这样一个例子:member/2
它是内置的并产生(有时)冗余的答案和memberd/2 https://stackoverflow.com/a/21971885没有这种冗余。实际的问题是:
二元素列表看起来像这样e
作为元素/成员?
?- Xs = [_,_], member(e, Xs).
Xs = [e,_A]
; Xs = [_A,e].
?- Xs = [_,_], member(e, Xs), member(e, Xs).
Xs = [e,_A]
; Xs = [e,e] % <--- redundant
; Xs = [e,e] % <--- redundant
; Xs = [_A,e].
?- Xs = [_,_], memberd(e, Xs).
Xs = [e,_A]
; Xs = [_A,e], dif(_A,e)
; false.
?- Xs = [_,_], memberd(e, Xs), memberd(e, Xs).
Xs = [e,_A]
; Xs = [_A,e], dif(_A,e)
; false.
如果您只想查看那些允许裁员的答案,您可以改为:
?- Xs = [_,_], member(e, Xs), \+ \+ call_nth(member(e, Xs), 2).
Xs = [e,_A]
; Xs = [_A,e].
换句话说,all的答案member/2
允许此类裁员。注意member/2
并不总是容易出现冗余。特别是,如果列表包含不同的(不可统一的)元素,则根本不存在冗余。这是一个常见的用例。
?- Xs = [a,b], member(X, Xs), \+ \+call_nth(member(X, Xs),2).
false.
事实上,在这种情况下,即在查询时X
, member/2
可能比memberd/2
.