Prolog: how to write n amount of characters of a string? - prolog

I'm really new to prolog and i have to write a predicate what takes in a string and an integer and writes out as many characters of that string as the integer value is. How can i do this ?
Example:
myPredicate('Hello',4). %will write out 'Hell'
myPredicate('New in prolog',6). %will write out 'New in'

format it's the appropriate predicate to perform formatted output, but it doesn't provide a truncation of values. Then you could define a service predicate like print_n/2:
6 ?- [user].
|: print_n(W,N) :- sub_atom(W,0,N,_,S),write(S).
% user://1 compiled 0.04 sec, 2 clauses
true.
7 ?- print_n(hello,3).
hel
true.
then format/2 can invoke your service predicate by means of #:
8 ?- format('hello ~#~n', [print_n(world,3)]).
hello wor
true.

Related

Prolog argument mode indicator causes output false

I am trying to use Prolog's argument mode indicators in the signature of my method (https://www.swi-prolog.org/pldoc/man?section=argmode).
Without the indicators, my function works as expected (eg. palindrome([1,2,1]) gives true):
palindrome(List) :-
reverse(List, List)
But when I say
palindrome(+List) :-
reverse(List, List)
I get false every time. I don't get any errors or warnings. I also tried the following but had no luck:
palindrome(+List) :-
reverse(+List, +List)
So I'm pretty sure I am using these indicators wrong somehow. Can anyone help? I am using SWI-Prolog and the SWISH online IDE.
Yes, wrong. You shouldn't be using them at all, in the code. Only in the comments.
+ is interpreted as a separate token:
6 ?- atom(+X).
false.
7 ?- +X =.. Z.
Z = [+, X].
8 ?- +X = + X.
true.
9 ?- +X = '+'(X).
true.
You could use the +-using predicate definition as you show, but it's rather pointless:
14 ?- [user].
bar(+X,+X).
|:
true.
15 ?- bar( + 1, +Z).
Z = 1.
There are languages that do let us declare the modes, like I think Mercury does. But not Prolog. In Prolog we only use this as comments, to guide our use and understanding of the code.

finding players in the same the team in prolog

I'm trying to solve a prolog question. I'm trying to print the players who is playing in Arsenal. I couldn't solve the problem.
player(rick,arsenal)
player(tom,dortmund)
player(paul,bayern)
player(tim,liverpool)
player(john,arsenal)
player(andrew,arsenal)
the output has to be:
?- sameteam(????)
X= [rick,john,andrew]
First, your facts need to be terminated with a "." to be correct Prolog syntax
player(rick,arsenal).
player(tom,dortmund).
player(paul,bayern).
player(tim,liverpool).
player(john,arsenal).
player(andrew,arsenal).
In "relational database fashion", let's first collect the ground atoms (in the sense of "logic atoms", i.e. "facts") that match the condition "plays at arsenal".
Fire up your preferred Prolog, and then:
?- [user].
|: player(rick,arsenal).
|: player(tom,dortmund).
|: player(paul,bayern).
|: player(tim,liverpool).
|: player(john,arsenal).
|: player(andrew,arsenal).
|: ^D% user://2 compiled 0.00 sec, 6 clauses
true.
?- player(Who,arsenal).
Who = rick ;
Who = john ;
Who = andrew.
Now we just need to "collect them into a list" and we can do that easily using setof/3:
?- setof(Who,player(Who,arsenal),Players).
Players = [andrew, john, rick].
This is all bog-standard "asking the database" work.
We can pack the above into a predicate for easier usage:
?- [user].
|: sameteam(Players) :- setof(Who,player(Who,arsenal),Players).
|: ^D% user://3 compiled 0.00 sec, 1 clauses
true.
?- sameteam(Players).
Players = [andrew, john, rick].

How to return two values from a basic predicate(?) in Prolog?

I just started going over Prolog about an hour ago and have already stumbled into a slight problem I am unsure about. I am writing a predicate (or function?) that takes a list and returns the min and max values. Right now, I am just looking at one of the special cases when the list has 1 item. For example, if you query minmax([5], X, Y). I want the predicate to return X=5 Y=5. I have this code:
minmax([X], X, X).
but it is returning X = Y, Y = 5. I know it is a true statement and trivial, but is there a way I can return X=5,Y=5 ???
It is returning what you think it is. X is 5 as is Y. The values are unified and so the interpreter shows the message X=Y, Y=5. You need to get out the Prolog textbook and read up on unification of terms.
You could just as easily say
foo(A,B) :- A = 5 , B is (A+A)/2 .
and query it:
?- foo(X,Y).
and get the same result. In the Prolog universe, there is only ever a single instance of the integer 5.
X=Y, Y=5 means that X and Y are now both equal to 5. It's just a different way of saying that; you really shouldn't care. If you print both values, you'll just get 5:
?- [user].
|: print_stuff :-
|: X = Y,
|: Y = 5,
|: write('X = '), writeln(X),
|: write('Y = '), writeln(Y).
|: % user://1 compiled 0.02 sec, 2 clauses
true.
?- print_stuff.
X = 5
Y = 5
true.

Prolog - Assert into a new database

:-dynamic listofQuestions/2.
myrule:-
write('P = '), write(Percent), write('-'),write(X),
( listofQuestions(Percent,X) -> true ; assert(listofQuestions(Percent,X)) ),
The code snippet might not be required to answer my question.
I want to assert to a blank 'listofQuestions' everytime I call my rule. This only happens if I close my prolog window and restart it.
Any suggestions?
abolish/1 removes all clauses of a given predicate from the database. Hence, just add a call to abolish(PredName/Arity) whenever you need to remove the information about this predicate. Beware that after abolishing the call to the dynamic predicate does not fail but reports an error.
12 ?- f(X,Y).
false.
13 ?- assert(f(a,b)).
true.
14 ?- f(X,Y).
X = a,
Y = b.
15 ?- abolish(f/2).
true.
16 ?- f(X,Y).
ERROR: user://2:67:
toplevel: Undefined procedure: f/2 (DWIM could not correct goal)
In SWI-Prolog, abolish works on static procedures, unless the prolog flag iso is set to true. If you intend to remove only dynamic predicates, you should better try retractall. Observe that in this case removal does not lead to an error being reported but to a failure.
17 ?- [user].
:- dynamic f/2.
|:
% user://3 compiled 0.00 sec, 264 bytes
true.
18 ?- f(X,Y).
false.
19 ?- assert(f(a,b)).
true.
20 ?- f(X,Y).
X = a,
Y = b.
21 ?- retractall(f(X,Y)).
true.
22 ?- f(X,Y).
false.

Prolog syntax - using function results

I am trying to perform a sum operation on every result of :
combination(0,_,[]).
combination(K,L,[X|Xs]) :-
K > 0,
el(X,L,R),
K1 is K-1,
combination(K1,R,Xs).
el(X,[X|L],L).
el(X,[_|L],R) :- el(X,L,R).
For example, the user will enter is_sum_equal_10 ([1,2,3,4,5,6,7]) and the result will be true if the sum of any of the permutations equals 10.
I am struggling with putting it all together, can someone please help me define the is_sum_equal_10 rule that uses the combination rule for each permutation?
OK, well it's pretty easy to write really, you just need a rule to say if a particular combination sums to 10, and then another extra one to count up through the different sizes of combination lists (which is required due to the way you wrote combination with the K that you need to decrease as you check the rule).
1 ?- [user].
|: combination(0,_,[]).
|: combination(K,L,[X|Xs]) :- K > 0,
|: el(X,L,R), K1 is K-1, combination(K1,R,Xs).
|: el(X,[X|L],L).
|: el(X,[_|L],R) :- el(X,L,R).
|:
|: totals_10([],10).
|: totals_10([X|Xs],T) :- N is T+X, totals_10(Xs,N).
|:
|: is_comb_sum_equal_10(Numbers,_,R) :- combination(R,Numbers,C), totals_10(C,0).
|: is_comb_sum_equal_10(Numbers,N,R) :- Rnext is R+1, Rnext =< N,
|: is_comb_sum_equal_10(Numbers,N,Rnext).
|:
|: is_sum_equal_10(Numbers) :- length(Numbers,N), is_comb_sum_equal_10(Numbers,N,0).
|:
% user://1 compiled 0.13 sec, 1,824 bytes
true.
2 ?- is_sum_equal_10([2,3,5]).
true .
3 ?- is_sum_equal_10([2,235,124,3,3347,5,2373]).
true .
4 ?- is_sum_equal_10([2,235,124,3,3347,6,2373]).
false.
5 ?- is_sum_equal_10([1,1,1,1,1,-1,1,1,1,1,12]).
false.
6 ?- is_sum_equal_10([1,1,1,1,1,-1,1,1,1,1,11]).
true ;
false.
Since you don't care about the actual list or how big it is in the is_sum_equal_10 thing, you can just sum the combinations as you go along, and even better, check the sum is correct as a rule for the base case. I think it's a bit neater if you subtract from the desired total to get to 0 at the base rather than adding up and checking at the end against the value you want. This gives you a very simple single ruleset to look for a certain sum.
7 ?- [user].
|: is_subset_sum(0,[]).
|: is_subset_sum(N,[_|Xs]) :- is_subset_sum(N,Xs).
|: is_subset_sum(N,[X|Xs]) :- R is N-X, is_subset_sum(R,Xs).
|:
% user://2 compiled 0.03 sec, 540 bytes
true.
8 ?- is_subset_sum(10,[3,5,6]).
false.
9 ?- is_subset_sum(10,[123,4,1,77,3,2,34]).
true .
10 ?- is_subset_sum(11,[0,2,4,6,8,10,12,14,16,18,20,22]).
false.
This approach is of course both much easier to understand, and a lot more efficient.

Resources