How can I write a procedure in prolog that tags each element in a list, associating a number with it - prolog

The result is a list of tag(N, X) structures, where N has values 1,2,3,. . . and X represents a list element. For example
?- tagit([wibble,33,junk,phew],L).
L = [tag(1, wibble), tag(2, 33), tag(3, junk), tag(4, phew)]
I'm new to Prolog and need to complete this please.

Do you know what list is?
list(X):- X=[].
[] is a list.
list(X):- X=[A|B], list(B).
[A|B] is a list if B is a list.
What is a taglist?
taglist(Y):- Y=[].
[] is a taglist.
taglist(Y):- Y=[C|D], C=tag(N,V), taglist(D).
[C|D] is a taglist if C=tag(N,V) with some N and V, and D is a taglist.
Can we put the two together, smashing them into one? Yes, we can:
taglist2(X,Y):- X=[], Y=[].
taglist2(X,Y):- X=[A|B], Y=[C|D], ...., taglist2(B,D).
What is A? What is V?
What is N? It is a number. First number is 1:
number(N,One):- N is One.
Next number is found from a previous one, as
number(N,Prev):- Next is Prev + 1, number(N,Next).
Can we smash the three of them together? Yes, we can. Try it, it's fun.

Related

Prolog lists inside the lists

I'm new to Prolog and what I'm trying to achieve is to define the tower-like type which contains lists of natural numbers. Each "floor" is supposed to have the same amount of "apartments" and I don't know how can I check it.
Assuming with "type" you mean a structure which can hold your data, I suggest using a list of lists, like this:
[[101,102,103],[201,202,203],[301,302,303]]
So now you need to check if each "floor" (sublist), has the same amount of elements. Counting the elements in a list is rather simple:
len([],0).
len([H|T],N1) :-
len(T,N),
N1 is N+1.
Which reads: an empty list [] has 0 elements. A list which can be splittet into a head element H and a rest list T has the length N1, if the length of T is N and N1 is calculated by N+1.
So what is missing? You need to go through all your sublists and get the length of the sublist. If the length of two sublists are different, then fail. If you reach the end with allways the same number, success. So the pattern would look like this:
isHotel(R):-
isHotel(R,_).
Add a placeholder for the counting, actual number of the second argument does not matter at this point.
isHotel([],_) .
If you got to a point where there are no floors left, accept for any number.
isHotel([CurrentFloor|T],N) :-
len(CurrentFloor,N),
isHotel(T,N).
If there are floors left (floorlist can be devided into the current floor CurrentFloor and all floors above T), count the rooms at this floor and go check with the left over floors T. The first time this is runs, the number N of rooms will be calculated and forwarded to every other call - therefore for the first time the calculation is just a calculation, in every other ecxecution it is a check as well. This leads to rejects if two lusts do not match in size. Please note this code does not check if the input is a list of lists of numbers.
Checked with SWISH:
?- isHotel([[101,102,103],[201,202,203],[301,302,303]]).
true.
?- isHotel([[101,102,103],[201,202,203],[301,302,3,03]]).
false.
?- isHotel([]).
true.

Counting the number of lists in a nested list

I am having troubles counting the number of lists in a nested list.
count_lists([H|T],R):-
atomic(H),!,
count_lists(T,NR),
R is NR+1.
count_lists([[H|T]|Rest],R):-
!,
count_lists([H|T],R1),
count_lists(Rest,R2),
R is R1+R2.
count_lists([],0).
First of all, I try the basic case where an element in the list is atomic and thus, I should increment the counter by one. (Also, I tried removing the atomic predicate because I figured that because of it, my code will compute the number of elements in a nested list, but it still doesn't work)
Then, if the first element is a list itself, I go recursively on it and on the remaining list, adding the results.
And the third clause is states that the number of nested lists in an empty list is 0.
?count_lists([[1,5,2,4],[1,[4,2],[5]],[4,[7]],8,[11]],R).
should return 8 but instead, returns 12.
I know it's been a while since you asked this, but here is the answer I think you were looking for:
count_lists([],1).
count_lists([H|T],Rez):-atomic(H),!,count_lists(T,Part),Rez is Part.
count_lists([H|T],Rez):-count_lists(H,Part1),count_lists(T,Part2),Rez is Part1+Part2.
This way, you count only the number of lists and not the number of elements within.
you need to distinguish lists from other elements, i.e.
count_lists(E,R):-
is_list(E),!,count_elems(E,N),
R is N+1.
count_lists(_,0).
count_elems([H|T],R):-
count_lists(H,Hc),
count_elems(T,Tc),
R is Hc+Tc.
count_elems([],0).
but the code is contrived, using library we can get it done in 1 step:
count_lists(E, R):-
maplist(count_lists, E, Cs) -> sum_list(Cs, S), R is S+1 ; R = 0.
the code can be understood only WRT maplist/N behaviour
?- maplist(_,a).
false.
?- maplist(_,[]).
true.
?- maplist(_,[1]).
ERROR: apply:maplist_/2: Arguments are not sufficiently instantiated
In your solution you forget that e.g. [1,2,3] = [1,2,3| []] or [1,2,3] = [1| [2| [3| []]]]. Thus, you're "over-counting", thanks to your first clause. For example:
?- count_lists([1,2,3], N).
N = 3.
But there's another problem. In your second clause, if you've a nested list that nests other lists, you don't count it. Not clear from the title if that's intended or if it's a bug.
You shouldn't have complicated yourself.
count([],1).
count([L1|L2],Rez):- count(L1,Rez1),count(L2,Rez2),Rez is Rez1+Rez2.
You take out all the elements in a list recursively until you are left out with the empty list which values 1.

Taking out the 2nd to last element - Prolog

I'm very new to Prolog and am trying to figure out exactly what is happening with this (function?) that takes out the 2nd to last element in a list.
remove([],[]).
remove([X],[X]).
remove([_,X],[X]).
remove([X|Xs], [X|Ys]) :-
Xs = [_,_|_],
remove(Xs,Ys).
I'm familiar with pattern matching, as I've done a little work in SML. The first one is clearly the base case, returning the empty list when we break it down. The second returns the same variable when there is only one left. The third looks as if it returns the last element, disregarding the 2nd to last? As for the inductive case, it will attach the head of the list to the new list if ...... (This is where I get completely lost). Could anyone explain what's happening in this function so I can have a better understanding of the language?
Elaborating on CapelliC's explanation:
remove([],[]).
An empty list is an empty list with the second-to-last element removed.
remove([X],[X]).
A single-element list is itself with the second-to-last element removed.
remove([_,X],[X]).
A two-element list with the second to last element removed is a list of one element consisting of the last element of the two-element list.
remove([X|Xs], [X|Ys]) :-
Xs = [_,_|_],
remove(Xs,Ys).
The second list is the first list with the second element removed, and share the same first element, IF:
The tail of the first list consists of at least two elements, AND
The tail of the second list is the tail of the first list with the second to last element removed
A set of clauses is a predicate, or procedure.
All first three are base cases, and the recursive one copies while there are at least 3 elements in the first list.
I would describe the behaviour like 'removes pre-last element'.
So, how to declaratively read
remove([X|Xs], [X|Ys]) :-
Xs = [_,_|_],
remove(Xs,Ys).
Most important is that you first realize what the :- actually means.
Head :- Body.
It means: Whenever Body holds, we can conclude that also Head holds. Note the rather unintuitive direction of the arrow. It goes right-to-left. And not left-to-right, as often written informally when you conclude something. However, the error points into the direction of what we get "out of it".
To better see this, you can enter Body as a query!
?- Xs = [_,_|_], remove(Xs,Ys).
Xs = [A, B], Ys = [B]
; Xs = [A, B, C], Ys = [A, C]
; ... .
So we get all answers, except those where Xs has less than two elements.
Please note that procedurally, things happen exactly in the other direction - and that is very confusing to beginners. Even more so, since Prolog uses two "non-traditional" features: chronological backtracking, and variables - I mean real variables, meaning all possible terms - not these compile time constructs you know from imperative and functional languages. In those languages variables are holders for runtime values. Concrete values. In Prolog, variables are there at runtime, too. For more to this, see Difference between logic programming and functional programming
There is also another issue, I am not sure you understood. Think of:
?- remove(Xs, [1,2]).
Xs = [1, A, 2]
; false.
What is removed here? Nothing! Quite the contrary, we are adding a further element into the list. For this reason, the name remove/2 is not ideal in Prolog - it reminds us of command oriented programming languages that enforce that some arguments are given and others are computed. You might at first believe that this does not matter much, after all it's only a name. But don't forget that when programming you often do not have the time to think through all of it. So a good relational name might be preferable.
To find one, start with just the types: list_list/2, and then refine list_removed/2 or list__without_2nd_last/2.
Annotated:
remove( [] , [] ) . % removing the 2nd last element from the empty list yields the empty list
remove( [X] , [X] ) . % removing the 2nd last element from a 1-element list yields the 1-element list.
remove( [_,X] , [X] ) . % removing the 2nd last element from a 2-element list yields the tail of the 2-element list
remove( [X|Xs] , [X|Ys] ) :- % for any other case...
Xs = [_,_|_], % * if the tail contains 2 or more elements, the list is 3 elements or more in length
remove(Xs,Ys). % we simply prepend the head of the list to the result and recurse down.
It should be noted that the last clause could re-written a tad more clearly (and a little more succinctly) as:
remove( [X1,X2,X3|Xs] , [X1|Ys] ) :- % for any other case (a list of length 3 or more)
remove([X2,X3|Xs],Ys). % we simply prepend the head of the list to the result and recurse down.
Or as
remove( [X1|[X2,X3|Xs]] , [X1|Ys] ) :- % for any other case (a list of length 3 or more)
remove([X2,X3|Xs],Ys). % we simply prepend the head of the list to the result and recurse down.

Haskell: brute force and maximum subarray problem

I am trying to solve the maximum sub array problem with a brute force approach i.e generating all the possible subarrays combinations. I got something that works but it's not satisfying at all because it produces way too many duplicated subarrays.
Does anyone knows a smart way to generate all the subarrays (in [[]] form) with a minimal number of duplicated elements ?
By the way, I'm new to Haskell. Here's my current solution:
import qualified Data.List as L
maximumSubList::[Integer]->[Integer]
maximumSubList x = head $ L.sortBy (\a b -> compare (sum b) (sum a)) $ L.nub $ slice x
where
-- slice will return all the "sub lists"
slice [] = []
slice x = (slice $ tail x) ++ (sliceLeft x) ++ (sliceRight x)
-- Create sub lists by removing "left" part
-- ex [1,2,3] -> [[1,2,3],[2,3],[3]]
sliceRight [] = []
sliceRight x = x : (sliceRight $ tail x)
-- Create sub lists by removing "right" part
-- ex [1,2,3] -> [[1,2,3],[1,2],[1]]
sliceLeft [] = []
sliceLeft x = x : (sliceLeft $ init x)
There are many useful functions for operating on lists in the standard Data.List module.
import Data.List
slice :: [a] -> [[a]]
slice = filter (not . null) . concatMap tails . inits
dave4420's answer is how to do what you want to do using smart, concise Haskell. I'm no Haskell expert, but I occasionally play around with it and find solving a problem like this to be an interesting distraction, and enjoy figuring out exactly why it works. Hopefully the following explanation will be helpful :)
The key property of dave4420's answer (which your answer doesn't have) is that the pair (startPos, endPos) is unique for each subarray it generates. Now, observe that two subarrays are distinct if either their startPos or endPos is different. Applying inits to the original array returns a list of subarrays that each have unique startPos, and the same endPos (equal to the number of elements in the array). Applying tails to each of these subarrays in turn produces another list of subarrays -- one list of subarrays is output per input subarray. Notice that tails does not disturb the distinctness between input subarrays because the subarrays output by invoking tails on a single input subarray all retain the same startPos: that is, if you have two subarrays with distinct startPoses, and put both of them through tails, each of the subarrays produced from the first input subarray will be distinct from each of the subarrays produced from the second one.
Additionally, each of the subarrays produced by the invocation of tails on a single subarray are distinct because, although they all share the same startPos, they all have distinct endPoses. Therefore all subarrays produced by (concatMap tails) . inits are distinct. It only remains to note that no subarray is missed out: for any subarray starting at position i and ending at position j, that subarray must appear as the j-i+1th list produced by applying tails to the i+1th list produced by inits. So in conclusion, every possible subarray appears exactly once!

Prolog Counter Problem

I am trying to write a procedure order(List,Result) that has a List as input and returns a list Result of ordered pairs such that:
the first element of the ordered pair is the position of the pair in the list, and
the second element of the ordered pair is the element from List n the corresponding position.
Example:
if List = [a,b,c,d], the procedure order(List,Result) outputs the list:
Result = [(1,a), (2,b),(3,c),(4,d)].
I am struggling with the counter for the position of the pair in the list. I have made attempts such as:
increment(Accum,Total):-
Total is Accum + 1.
order([],[]).
order([Head|Tail],Result):-
order(Tail, NewTail),
NewCount is Count + 1,
increment(NewCount,Count),
Result = [(Count,Head)|NewTail].
Please help anyone?
The two clauses: NewCount is Count + 1 and increment(NewCount,Count) basically have the same meaning. You didn't make clear that Count is an input variable and it has a base case of 1, so Prolog didn't know where to start unifying values for it. For example, you should use Count as an input argument as follows (it doesn't change much if compared with your version):
order([],[], _).
order([Head|Tail],[(Count,Head)|NewTail], Count):-
NewCount is Count + 1,
order(Tail, NewTail, NewCount).
order(List, Result ):- order(List, Result, 1).
If you're OK with using findall/3 then this is probably the simplest solution:
order(List, Result) :-
findall(Index-Elem, nth1(Index, List, Elem), Result).
Note that here the key-value pairs are represented using the term -/2, which is how pairs are usually represented in Prolog, e.g. this is what keysort/2 expects.
order(List,Result) :-
findall((N,E),(
append(L0,[E|_],List),
length([_|L0],N)),
Result).

Resources