Converting 1st letter of atom in Prolog - prolog

How to convert 1st letter of an atom in uppercase letter in LPA prolog? the only way I know is using 'lwrupr'. But it capitalizes all the letters.

I don't have LPA Prolog available, but here is an educated guess, resulting from a quick read of reference manual: take the first letter from the atom, make it upper case, and rebuild the word
first_char_uppercase(WordLC, WordUC) :-
atom_chars(WordLC, [FirstChLow|LWordLC]),
atom_chars(FirstLow, [FirstChLow]),
lwrupr(FirstLow, FirstUpp),
atom_chars(FirstUpp, [FirstChUpp]),
atom_chars(WordUC, [FirstChUpp|LWordLC]).
In SWI-Prolog, we can test it defining the missing builtin lwrupr/2 like this
lwrupr(Low, Upp) :- upcase_atom(Low, Upp).
and we get
?- first_char_uppercase(carlo,X).
X = 'Carlo'.
?- first_char_uppercase('Carlo',X).
X = 'Carlo'.

Related

Alternative to string_upper/2

Machine, which my code is supposed to work on, for some reason doesn't know predicate string_upper/2. Are there any alternatives? Eventually, what would code for this predicate look like?
The example you gave in the comments is actually not a string but a pair of atoms. Since you already opted to use upcase_atom/2, in the code you deleted from your post, I'd point out that this built-in is only working in one direction, that is if the the first argument is atomic. Consider the following queries:
?- upcase_atom(bo,'BO'). % Is 'BO' the uppercase version of bo?
true. % Yes, it is.
?- upcase_atom(bo,B). % What's the uppercase version of bo?
B = 'BO'. % It's 'BO'
?- upcase_atom(B,'BO'). % What atom has 'BO' as uppercase version?
ERROR: upcase_atom/2: Arguments are not sufficiently instantiated
?- upcase_atom(B,1). % What atom has 1 as uppercase version?
ERROR: upcase_atom/2: Arguments are not sufficiently instantiated
Your example query, from your deleted code, is ?- divideIt(a-b).. The atom a is unified with the variable V in the head of the rule divideIt/1. Then Prolog calls the first goal upcase_atom(V,ve) that has to fail because the atom ve is not the uppercase version of the atom a. Consequently your example query fails as well. If you apply the following minor changes to your predicate, it yields the desired result:
divideIt(V-W) :-
upcase_atom(V,Ve), % <- Ve (=variable) instead of ve (=atom)
write(Ve),
write('-'), % <- '-' instead of "-"
upcase_atom(W,We), % <- We (=variable) instead of we (=atom)
write(We).
?- divideIt(a-b).
A-B
true.
Break the string into a list of character codes. Then convert those codes into the appropriate upper case code if necessary before reconstructing the string. A more complete answer would require knowing which prolog you're using, its available predicates & how it represents strings.
You might want to read up on different Prolog's handling of characters, Unicode and strings. For this, the SWI-Prolog implementation has some good documentation:
How traditional(Edinburgh), ISO & SWI prolog handles characters: 4.2 Character Representation
How ISO & SWI prologs support Unicode 2.16.1.8 Unicode Prolog source
How SWI has a specific string-type object which uses quotes to denote them: 5.2 The string type and its double quoted syntax

Check if any element in List begins with a specific character

I've a list of words, for example [cola,fanta,pepsi] and I want to write a predicate that checks if any of the elements begins with the character specified.
My code so far is as follows:
chk_first_letter(Char,[]):-fail.
chk_first_letter(Char, [H|T]):-
perform_check(Char, H);
chk_first_letter(Char, T).
perform_check(Char,[First|_]):-memberchk(Char, First).
However consulting my file and calling chk_first_letter(p,[cola,fanta,pepsi]) gives me no even if pepsi begins with a p.
I've tried with Char==First instead of memberchk(Char,First) but it didn't work either. I'm not sure about the difference.
You have a list of atoms, and your perform_check/2 compares two atoms. An atom is not a list of characters! You need to use atom processing, for example:
perform_check(First, Word) :-
sub_atom(Word, 0, 1, _After, First).
http://gprolog.univ-paris1.fr/manual/html_node/gprolog043.html#sec200
There are a bunch of other built-ins in this section that could be used, for example for breaking the atom into characters or character codes (atom_chars/2 and atom_codes/2). But what sub_atom/5 also allows you to do easily:
prefixes of any length:
sub_atom(Word, 0, _Length, _After, Prefix).
suffixes:
sub_atom(Word, _Before, _Length, 0, Suffix).
First attempt:
chk_first_letter(Char, Atoms) :- member(A, Atoms), atom_chars(A, [Char|_]).
atom_chars/2 it's an ISO predicate.
Your code it's almost working, can be simplified this way:
chk_first_letter(Char, [H|T]):-
atom_chars(H, [Char|_]);
chk_first_letter(Char, T).
memberchk expects to be called with a list as the second argument. In your case, you're providing it with a single character.
And then you can probably do away with it altogether by taking advantage of unification:
perform_check(Char,[Char|_]).
This assumes your string type is a list of characters (whatever the character format). If you intend to operate on atoms directly, you could do it this way instead:
perform_check(Char,String) :- atom_concat(Char,_,String)
There would be a few more steps to make your code more idiomatic, but this seems to be the actual wrong part of it.

Converting Terms to Atoms preserving variable names in YAP prolog

Is there a way to configure YAP (and/or SWI prolog) so they will preserve variable names in any call to term_to_atom/2 ?.
For example, when I execute this:
term_to_atom(member(X, [1,2]), A).
I obtain this answer:
A = 'member(_131405,[1,2])'
Where X has been replaced by its internal representation.
However, I would like to get this answer instead:
A = 'member(X,[1,2])'
Thanks for any help!
There are two issues involved. How to get the variable name X into the system, and how to get a term with such a variable into the atom.
The X you type in is read by the top level which converts it to a regular variable which does not have a name associated. Let's see that in YAP:
?- read(Term).
|: X+3*Y+X.
Term = _A+3*_B+_A
The |: is YAP's prompt for input. And we have entered X+3*Y+X. However, the variable Term contains _A and _B (names chosen by the top level) in place of X and Y. So the information is lost and cannot be restored once it is read by read/1.
You have to access that information differently with the more general built-in for reading read_term/2,3 and the option variable_names/1.
?- read_term(T,[variable_names(Eqs)]).
|: X+3*Y+X.
Eqs = ['X'=_A,'Y'=_B],
T = _A+3*_B+_A
So the read option variable_names/1 gives you the information to restore the variable names. For each named variable read by read_term/2 there is a structure Name = Variable where Name is an atom representing the variable name. Above, 'X' is the name capital X.
Anonymous variables, that is variables whose name is _, do not occur in the list of variable names. They can be rapidly extracted like so:
?- read_term(T,[variable_names(Eqs)]),
term_variables(Eqs, Named),
term_variables(Named+T, Vars),
append(Named, Anons, Vars).
So much for the reading.
Now for the writing. We cannot write the term directly but have to accompany it with the list Eqs. Let's call the new predicate term_to_atom(Term, Eqs, Atom). In both YAP and SWI there is with_output_to(Output, Goal) which writes the output of Goal to different destinations like atom(A). So you can now use write_term/2 to write the term as you please. An example:
?- with_output_to(atom(A),write_term('a b'+X,[quoted(true)])).
A = '\'a b\'+_131284'.
The variable _131284 looks very ugly. To get variables associated with their names for printing we can implement term_to_atom/3 as follows:
term_to_atom(T, Eqs, A) :-
with_output_to(atom(A), write_term(T,[variable_names(Eqs),quoted(true)]) ).
And use it like so:
?- read_term(T,[variable_names(Eqs)]), term_to_atom(T, Eqs, Atom).
|: X+3*Y+X.
Atom = 'X+3*Y+X',
Eqs = ['X'=_A,'Y'=_B],
T = _A+3*_B+_A
variable_names/1 exists as a write option in ISO, Minerva, Jekejeke, GNU, B, SWI, YAP, and SICStus.
In SICStus, the originator of writing terms to lists, one writes:
:- use_module(library(codesio)).
term_to_atom(T, Eqs, Atom) :-
write_term_to_codes(T, Codes, [variable_names(Eqs),quoted(true)]),
atom_codes(Atom, Codes).
The following was an ISO incompatible work around for YAP prior to 6.3.4. It is no longer necessary. As for the differences to a separate write option: term_to_atom/3 as defined below interferes with constraints and does not correctly render '$VAR'/1.
But for the moment we can only approximate the ideal option
variable_names/1. To print terms with our own variable names,
variables have to be substituted in YAP by '$VAR'(Codes) where
Codes is a list of character codes. This does not do exactly the
same, but it is very close. This goes into a file:
:- use_module(library(apply)).
:- use_module(library(lambda)).
write_eqs_term(T, Eqs) :-
\+ \+ (
maplist(\Eq^( Eq = (N='$VAR'(Chs)), atom_codes(N,Chs)), Eqs),
write_term(T,[numbervars(true),quoted(true)])
).
term_to_atom(T, Eqs, A) :-
with_output_to(atom(A), write_eqs_term(T, Eqs) ).
For SWI, you would have to replace atom_codes(N,Chs) by N = Ch.
and install library(lambda) first. It's pre-installed in YAP.

Problem when reading backslash in Prolog

I'm writing a lexer in Prolog which will be used as a part of functional language interpreter. Language spec allows expressions like for example let \x = x + 2; to occur. What I want lexer to do for such input is to "return":
[tokLet, tokLambda, tokVar(x), tokEq, tokVar(x), tokPlus, tokNumber(2), tokSColon]
and the problem is, that Prolog seems to ignore the \ character and "returns" the line written above except for tokLambda.
One approach to solve this would be to somehow add second backslash before/after every occurrence of one in the program code (because everything works fine if I change the original input to let \\x = x + 2;) but I don't really like it.
Any ideas?
EDIT:
If anyone should have similar problems, that's how I solved it:
main(File) :-
open(File,read,Stream),
read_stream_to_codes(Stream, Codes),
lexer(X,Codes,[]),
... invoke other methods
Where did you get the string let \x = x + 2; from?
If it is in your Prolog program: yes, you have to double the backslashes.
If it is from an external file: How do you read it from there? Maybe that predicate is interpreting the backslash specially.
I got inspired by that problem and wrote a bit of code, which should be portable to all Prolog implementations:
% readline(-Line)
%
% Reads one line from the current input. The line is then returned as a list
% of one-character atoms, excluding the newline character.
% The returned line doesn't tell you whether the end of input has been reached
% or not.
readline(Line) :-
'readline:read'([], Reversed),
reverse(Line, Reversed).
'readline:read'(Current, Out) :-
get_char(C), 'readline:append'(C, Current, Out).
'readline:append'(-1, Current, Current) :- !.
'readline:append'('\n', Current, Current) :- !.
'readline:append'(C, Current, Line) :-
'readline:read'([C | Current], Line).
I tried it, and it worked for me.
Of course, as explained in question 1846199, you can also use read_line_to_codes/2.

Translate Prolog Words

I'm working on this this wonderful Prolog project and I'm stuck at this situation where I need to translate certain words into other words (e.g "i" into "you". "my into "your")
This is what I've done and I'm pretty sure it's kinda iffy. I enter the sentence and when It goes to convert it only changes the one word then goes on wacky on me. (e.g. "i feel happy" changes to "you" then it crashes.)
translate([]).
translate([H|T], [NewH|NewT]):-
means(H,NewH);
spit(T,NewT).
means(i,you).
means(my,your).
means(mine,yours).
Here's the fix:
translate([], []).
translate([H|T], [NewH|NewT]):-
means(H, NewH),
translate(T,NewT).
means(i, you) :- !.
means(my, your) :- !.
means(mine, yours) :- !.
means(X, X).
The changes are as follows:
I fixed the missing parameter to the first definition of translate (it's considered a completely independent function if the number of parameters don't match).
I'm calling translate on the rest of the list when the first item is translated.
I'm asserting that every word means itself unless specified otherwise. The :- ! part means if you match this, don't try the rest (this is to avoid lists always matching with themselves).
Example usage:
?- translate([this, is, i], X).
X = [this, is, you].

Resources