Если ваша система Prolog поддерживает clpfd , вы можете использовать следующую реализацию xpto/3
.Реализация сохраняет логическую чистоту !
Давайте реализуем xpto/3
на основе list_counts/2
, мета-предикатов tfilter/3
иmaplist/3
и (#=<)/3
.(#=<)/3
является усовершенствованной версией ограничения (#=</2)
.
:- use_module(library(clpfd)).
:- use_module(library(lambda)).
xpto(Xs,Ys,N) :-
list_counts(Xs,Css0),
tfilter(N+\ (_-V)^(N #=< V),Css0,Css1),
maplist(\ (K-_)^K^true,Css1,Ys).
Давайте запустим запросы, которые вы задали в своих вопросах:
?- xpto([a,a,a,b,b,c],Out,3).
Out = [a]. % <b>succeeds deterministically</b>
?- xpto([a,a,a,b,b,c],Out,2).
Out = [a,b]. % <b>succeeds deterministically</b>
Поскольку код, используемый в этой реализации, monotone , мы можем задавать довольно общие запросы и по-прежнему получать логически обоснованные ответы :
?- xpto([a,a,a,b,b,c],Out,N).
Out = [], N in 4..sup ;
Out = [a], N = 3 ;
Out = [a,b], N = 2 ;
Out = [a,b,c], N in inf..1 .
Теперь, как будут выглядеть ответы, если первый аргумент содержит переменные?
?- Xs = [_,_],xpto(Xs,Out,N).
Xs = [_A,_A], Out = [], N in 3..sup ;
Xs = [_A,_A], Out = [_A], N in inf..2 ;
Xs = [_A,_B], Out = [], N in 2..sup, dif(_A,_B) ;
Xs = [_A,_B], Out = [_A, _B], N in inf..1, dif(_A,_B) .