Fill unbound variables by a range - prolog

lets say that L is L = [[1,100,_], [200, _,94]].
I have a code where I use
append(List, L), L ins 1..90, .......
L ins 1..90 is false because there are elements which are not in the domain. But I want L ins 1..90 to only specify the unbound variables not the whole list. Is there a way for that?
Thanks

List = [[1,100,_], [200, _,94]],
append(List, L),
partition(ground, L, _, Unground),
Unground ins 1..90

Related

How to rotate using difference-list in Prolog

Using difference-lists,How to rotate a given list by moving the first two elements to the end of the list, so that [a,b,c,d] becomes [c,d,a,b].
If you're being provided with a difference list, then can use:
?- L = [a,b,c,d,e,f|R], L = [H1, H2|T], R = [H1, H2].
T = [c,d,e,f,a,b].
As a DCG (more human-friendly than difference lists), in swi-prolog:
% For remainder/1
:- use_module(library(dcg/basics)).
% Show lists of codes nicely
:- portray_text(true).
rotate2, Rem, [E1, E2] --> [E1, E2], remainder(Rem).
Result in swi-prolog:
?- phrase(rotate2, `abcdef`, R).
R = `cdefab`.
Alternatively, if you need the tail also:
rotate2_tail([A, B|T]) --> T, [A, B].
?- phrase(rotate2_tail(`abcdef`), L, R).
L = `cdefab|R`.
As a third method (note that there is no actual difference list specified in the question):
?- L = [a,b,c,d,e,f], L = [H1, H2|T], append(T, [H1, H2], L2).
L2 = [c,d,e,f,a,b].

how to remove the first two elements and the last two elements of a list?

the following code is not possible, because it can only remove the first two or last two.
delements(L,L1):- append([_,_],L1,L),append(L1,[_,_],L).
You should not reuse L1 and L in the same list. You need an extra variable here:
delelements(L, R) :-
append(M, [_, _], L),
append([_, _], R, M).
So here M is a list that contains the elements of L, except for the last two. R is a variant of M, except that the first elements are removed.
This then give us:
?- delelements([1,4,1,3,0,2,2,5], R).
R = [1, 3, 0, 2] ;
false.
Furthermore we do not need to use append/3 [swi-doc] to remove a fixed number of elements from the head. We can use unification for this:
delelements(L, R) :-
append([_, _ | R], [_, _], L).
trim(X,Y) :-
append([[_,_],Y,[_,_]],X).

Why the end of result list is not []?

I tried to output a list only contain the unique element. But the result is not perfect.
list_concatenation([],L,L).
list_concatenation([X1|L1],L2,[X1|L3]) :-
list_concatenation(L1,L2,L3).
list_member(X, [X|_]).
list_member(X, [_|TAIL]) :- list_member(X,TAIL),!.
toset([],_).
toset([X|TAIL],SET):-
list_member(X,SET),
toset(TAIL,SET).
toset([X|TAIL],SET):-
\+ list_member(X,SET),
list_concatenation([X],SET,NEWSET),
toset(TAIL,NEWSET).
For example:
?- toset([1,1,2,3],X).
the result should be 'X = [1, 2, 3]' but now, it is 'X = [1, 2, 3|_16998]'
You actually implement the toset/2 the wrong way. You actually use list_member/2 here to add an element to the list. Indeed, if you use a free variable, you get:
?- list_member(2, L).
L = [2|_3616] ;
L = [_3614, 2|_3622].
The list_member/2 itself, is not correctly implemented as well. The cut (!) here prevents to keep yielding values. You thus should remove the cut:
list_member(X, [X|_]).
list_member(X, [_|Tail]) :-
list_member(X,Tail).
This thus can yield all possible lists where 2 is a member:
?- list_member(2, L).
L = [2|_3412] ;
L = [_3410, 2|_3418] ;
L = [_3410, _3416, 2|_3424] ;
L = [_3410, _3416, _3422, 2|_3430] ;
...
But now the problem still remains: you should not use list_member/2 here to add elements to the list, you can use an accumulator here that keeps track of the elements already yielded, and then eventually return that accumulator, like:
toset(L, S) :-
toset(L, [], S).
toset([], A, S):-
reverse(A, S).
toset([H|T], A, L) :-
( member_list(H, A)
-> toset(T, [H|A], L)
; toset(T, A, L)
).
We thus keep prepending the values to the accumulator, and in the end, we reverse/2 [swi-doc] the accumulator, and return that as a result.

How to convert an input from L to [H|T] in prolog?

say if I have to create a function in prolog:
dosomething(L).
how can I make it into something that does the same thing as:
dosomething([H|T]) where L = [H|T] so I can split the list?
You can unify L with [H|T]:
dosomething(L) :- L = [H|T], ...
which is the same as:
dosomething([H|T]) :- ...
Only if L is [] (or is not a list) then it cannot unify with [H|T]:
?- [H|T] = [].
false.

List in certain range

I have a predicate that is supposed to form a list from list, taking into a new list only these numbers that are in a certain range. The predicate works, but suppose that I want to get a list not including bounds.
So I change the condition A >= L, A =< R to A > L, A < R, but then I only get "True", and Prolog outputs nothing.
What could be a problem here?
My code is:
range([], _, _, []).
range([A|L1], L, R, [A|L2]) :-
A>L,
A<R,
range(L1, L, R, L2).
range([A|L1], L, R, L2) :-
A=<L;
A>=R,
range(L1, L, R, L2).
This is what program outputs:
range([1,2,3,4,5], 1,4, X).
?- range([1,2,3,4,5,6,7,8,9,10], 1,3, X).
true .
This is what I want it to output:
?- range([1,2,3,4,5,6,7,8], 1, 5, X).
X = [2,3,4] .
I think you forgot needed parenthesis
range([A|L1], L, R, L2) :-
( A=<L ; A>=R ),
range(L1, L, R, L2).
otherwise, when A=<L, you loose the recursive call, and then variables remain not instantiated.
Priority of the conjunction and disjuntion, , and ;, makes it necessary to write the third clause as:
range([A|L1], L, R, L2) :-
( A=<L
; A>=R
),
range(L1, L, R, L2).

Resources