Related
I'm working on this prolog assignment where I must parse an user-inputted list of string characters (specifically "u"), and determine if all the elements are equal to the string "u". If they are, then it returns the number of elements, if not, it returns false. For example:
uA(-Length,+String,+Leftover) //Prototype
?- uA(L,["u","u","u"],[]).
L = 3 .
?- uA(L,["u","u","d"],[]).
false.
I have a decent grasp on how prolog works, but I'm confused about how lists operate. Any help would be greatly appreciated. Thanks!
Edit: I made some headway with the sort function (thank you!) but I've run into a separate problem.
uA(Length, String) :-
sort(String, [_]),
member("u", String),
length(String, Length).
This does mostly what I need it to, however, when I run it:
?- uA(L, ["u", "u", "u"]).
L = 3 ;
L = 3 ;
L = 3.
Is there any way to make it such that it only prints L = 3 once? Thanks!
If you want to state that all list items are equal, there is no need to sort the list first.
Simply use library predicate maplist/2 together with the builtin predicate (=)/2:
?- maplist(=(X), Xs).
Xs = []
; Xs = [X]
; Xs = [X, X]
; Xs = [X, X, X]
; Xs = [X, X, X, X]
… % ... and so on ...
First of all, be careful with double-quoted terms in Prolog. Their interpretation depends on the value of the standard double_quotes flag. The most portable value of this flag is codes, which makes e.g. "123" being interpreted as [49,50,51]. Other possible values of this flag are atom and chars. Some Prolog systems, e.g. SWI-Prolog, also support a string value.
But back to your question. A quick way to check that all elements in a ground list are equal is to use the standard sort/2 predicate (which eliminates duplicated elements). For example:
| ?- sort(["u","u","u"], [_]).
yes
| ?- sort(["u","u","d"], [_]).
no
As [_] unifies with any singleton list, the call only succeeds if the the sorting results in a list with a single element, which only happens for a non-empty ground list if all its elements are equal. Note that this solution is independent of the value of the double_quotes flag. Note also that you need to deal with an empty list separately.
My approach is to check if every element in the list is the same or not (by checking if the head of the list and it's adjacent element is the same or not). If same then return True else false. Then calculate the length of every element is the same in the list.
isEqual([X,Y]):- X == Y , !.
isEqual([H,H1|T]):- H == H1 , isEqual([H1|T]).
len([],0).
len([_|T],L):- len(T,L1) , L is L1+1.
goal(X):- isEqual(X) , len(X,Length) , write('Length = ') , write(Length).
OUTPUT
?- goal(["u","u","u"]).
Length = 3
true
?- goal(["u","u","a"]).
false
you can do it this way. Hope this helps you.
I'm trying to develop code in prolog to capture items with frequency 0. Look at the example, the tuple:
[[1,31],[2,0],[3,21],[4,0],[5,0]]
Where each element is something else with 2 elements each, so the elements that should be captured are 2, 4 and 5, for frequency 0. The code below represents the idea:
match([],_).
match([[A,Y]|Tail],[A|Tail2]):- Y==0,match(Tail,[Tail2|A]),!.
match([[_,_]|Tail],X):- match(Tail,X).
Two parameters are passed: A tuple containing the set of target values and frequencies,
(["Target value", "frequency"], ["target value", "frequency"], ...]
And a second parameter that is a variable, it receives the target elements. However, the abstraction I had to develop the code is not correct, because the results are not as expected. I have gone round step by step to understand, modified several things and the result is always the same ... A list with only 2 elements is returned in any case (even if there is only one target with a frequency of 0).
Example with 3 frequency targets 0:
?- match([[1,31],[2,0],[3,312],[4,0],[5,0]],X).
X = [2|4].
Expected result for this case: X = [2,4,5].
Example with 1 frequency target 0:
?- match([[1,31],[2,0],[3,312],[4,312],[5,123]],X).
X = [2|_9998].
Expected result for this case: X = [2].
Someone can help me?
You could opt to describe the resulting list with DCGs like so:
match(Pairs,ZFs) :- % the items with frequency 0
phrase(zeros(Pairs),ZFs). % are described by zeros//1
zeros([]) --> % the empty list
[]. % contains no items
zeros([[I,0]|Is]) --> % if the frequency is 0
[I], % the item is in the list
zeros(Is). % the same for the remaining items
zeros([[I,F]|Is]) --> % if the frequency
{dif(F,0)}, % is not 0, the item isn't in the list
zeros(Is). % the same for the remaining items
Thus the two example queries in your post yield the desired results:
?- match([[1,31],[2,0],[3,21],[4,0],[5,0]],X).
X = [2,4,5] ? ;
no
?- match([[1,31],[2,0],[3,312],[4,312],[5,123]],X).
X = [2] ? ;
no
You're very close! Just two little issues:
Currently when an empty list is passed it, you say the result can be anything (_). I highly doubt this is what you want; the output for an empty list shoudl be an empty list as well.
The recursive call in the second clause is not correct. What you want the result to be is A followed by the result of the recursive call (Tail2). However, for some reason you wrote the recursive call with also A in it. I can't quite tell how you got to this, but you should just get Tail2 on its own.
Additionally, you can avoid writing Y==0 by directly writing it in the head of the clause. The resulting code then looks like this:
match([],[]).
match([[A,0]|Tail], [A|Tail2]) :- match(Tail, Tail2), !.
match([[_,_]|Tail], X) :- match(Tail, X).
?- match([[1,31],[2,0],[3,312],[4,0],[5,0]],X).
X = [2, 4, 5]
?- match([[1,31],[2,0],[3,312],[4,312],[5,123]],X).
X = [2]
I'm new to Prolog and I'm having trouble figuring out how to find the second minimum in the list that includes numbers and letters. When it includes a letter it should display an error and when it has one number then it should display an error. So far I have this but I'm not sure how to start off my code for having letters...
secondMin([_]) :-
print("ERROR: List has fewer than two unique elements."),
!.
secondMin(List, M2) :-
min_list(List, M1),
delete(List, M1, List1),
min_list(List1, M2).
The output should look like this:
?- secondMin([17,29,11,62,37,53], M2).
M2 = 17
?- secondMin([512], M2).
ERROR: List has fewer than two unique elements.
?- secondMin([7,5.2,3,6,-3.6,9,-2], M2).
M2 = -2
?- secondMin([12,2,b,7], M2).
ERROR: "b" is not a number.
?- secondMin([3,3,3], M2).
ERROR: List has fewer than two unique elements.
The easiest, but imperative, approach is to use maplist to determine whether there are any non-numbers. Then use sort to get the unique, second min.
secondMin(L, M) :-
( maplist(number, L)
-> ( sort(L, [_,Second|_])
-> M = Second
; print("List has fewer than two unique elements.")
)
; print("List has non-numeric elements")
).
As #repeat has pointed out in his comment, the above solution is "naive" in the sense that, although it produces a correct result for a valid input, it doesn't have appropriate error handling other than to display a diagnostic message but then succeed.
Here's a more thorough implementation which raises on exception when the first argument isn't defined as expected:
secondMin(L, M) :-
( ground(L)
-> ( is_list(L),
maplist(number, L)
-> ( sort(L, [_,Second|_])
-> M = Second
; throw('List has fewer than two unique elements')
)
; throw('First argument is not a list of numbers')
)
; throw(error(instantiation_error, _))
).
I'm trying to write a palindrome function in Prolog. I know I could just use something like
palindrome(List) :- reverse(List, List).
But I'm trying to figure out a way without using the built in reverse. I've created my own reverse rule:
rev([], []).
rev([H|T], X) :- rev(T, Y), append(Y, [H], X).
And what I'd like is, given a list, say [a,b,c,d], I'd like to do something like "X = rev([a,b,c,d]), but I'm really not sure whether this is possible in Prolog.
If it is, the way I would write my palindrome function would be something like:
palindrome(List) :- append(L1, rev(L1), List).
Is it possible to do what I'm trying to do - i.e. X = rev([a,b,c,d])?.
Thanks.
Palindromes are lists that read the same from front to back and from back to front. So the example you have given, [a,b,c,d] and it's reversal, constitute a palindrome if the first is directly followed by the second: [a,b,c,d,d,c,b,a]. Since you are trying to describe specific kinds of lists, it is very tempting to use Prolog DCGs for the task. With them you can define palindromes like so:
palindrome(X) :-
phrase(palindrome,X).
palindrome --> % base case for even number of elements
[].
palindrome --> % base case for odd number of elements
[A].
palindrome --> % general case: a palindrome is
[A], % some element A...
palindrome, % ... followed by a palindrome ...
[A]. % ... followed by element A
The most general query is producing palindromes with variables for each position:
?- palindrome(P).
P = [] ? ;
P = [_A] ? ;
P = [_A,_A] ? ;
P = [_A,_B,_A] ? ;
P = [_A,_B,_B,_A] ? ;
P = [_A,_B,_C,_B,_A] ?
...
Or alternatively you can test if a specific list is a palindrome:
?- palindrome("rats live on no evil star").
yes
?- palindrome([1,2,3,2,1]).
yes
?- palindrome([a,b,c,d]).
no
?- palindrome([a,b,c,d,d,c,b,a]).
yes
If you insist on using list reversal you can define the relation like so:
list([]) -->
[].
list([X|Xs]) -->
[X],
list(Xs).
invlist([]) -->
[].
invlist([X|Xs]) -->
invlist(Xs),
[X].
palindrome --> % a paindrome is
list(L), % a list followed
invlist(L). % by its reversal
palindrome --> % a palindrome is
list(L), % a list followed by
[_A], % some element
invlist(L). % then by the reversed list
The first of the above queries produces the answers in a different order now, namely the solutions with an even number of elements first:
?- palindrome(P).
P = [] ? ;
P = [_A,_A] ? ;
P = [_A,_B,_B,_A] ? ;
P = [_A,_B,_C,_C,_B,_A] ?
...
The other example queries yield the same result. However, the first definition seems to be clearly preferable to me. Not only because it is shorter as there is no need for additional DCG rules but also because it is producing the results in a fair order: empty list, one element, two elements, ... With the second version you get all the lists with an even number of elements first and there are infinitely many of those. So you never get to see a solution with an odd number of elements with the most general query.
I have to define a list in which:
1 is a member
if n is a member, so are 2n+1 and 3n+1
So the list is infinite and must be sorted. When loaded to GHCi, the command:
"take 10 theList"
will produce:
[1,3,4,7,9,10,13,15,19,21]
Below are my codes:
theList = ([1] ++ concat [[(x*2+1),(x*3+1)]|x<-theList])
It seems to work except for that it is not sorted, the same command as above produces:
[1,3,4,7,10,9,13,15,22,21]
Does anyone have any idea to sort that out?
Thanks
The problem can be though of as a infinite binary tree (A and B are labels for the branches):
1__ B
| 4___
| \ 13 ...
A 3_ \
| \ 9 ...
7 10
...
Thinking about it this way, we can see that we want to write a function ("listify") that converts the "tree" into a sorted list. This is where Haskell is really nice: if we have a function (merge) that takes two (infinite) sorted lists and merges them into one sorted list (you should write this function), then listify-ing the tree is simply listify-ing the two branches, merging them and putting the root at the start, i.e. in the tree above
1:merge (listify A) (listify B)
Since this is homework I won't say much more, but any branch of the tree is entirely determined by the root node, so the type signature of listify can be Integer -> [Integer]. And once you have listify, then theList = listify 1.
Another way of seeing this is as a filtered list of integers. The number n is part of the sequence if n = 1 (mod 2) and (n-1)/2 is a part of the sequence, or if n = 1 (mod 3) and (n-1)/3 is a part of the sequence.