3

I'm working on a URI parser in Prolog, but at the moment I'm stuck with something much simpler. I am exploring a string to find a particular char, ":", and when I find it, I want to have a string that only contains the concatenated chars before it.

This program:

% caratteri speciali
colonCheck(S) :-
   string_to_atom([S], C),
   C = ':'.                        % S==:

headGetter([H|T], [H]) :-
   !.

% struttura uri
uri(Scheme, Userinfo, Host, Port, Path, Query, Fragment).

% parsing uri
parsed_uri(UriInput, uri(Scheme,Userinfo,Host,Port,Path,Query,Fragment)) :-
   scheme(UriInput, uri(S,Userinfo,Host,Port,Path,Query,Fragment)),
   not(headGetter(UriInput, ':')),
   !,
   string_to_atom([S], Scheme).

% controllo Scheme, in ingresso ho i dati da controllare e l'oggetto uri che 
% mi servirà per inviarlo al passaggio successivo ho trovato i due punti
scheme([H|T], uri(Scheme,Userinfo,Host,Port,Path,Query,Fragment)):-
   colonCheck(H),
   !,
   end(Scheme).
% non trovo i due punti e procedo a controllare il prossimo carattere
% (la testa dell'attuale coda)
scheme([H|T], uri(Scheme,Userinfo,Host,Port,Path,Query,Fragment)):-
   not(colonCheck(H)),
   scheme(T, uri(This, Userinfo,Host,Port,Path,Query,Fragment)),
   append([H], This, Scheme).

%fine computazione
end([S]).

Gives this result:

?- scheme("http:", uri(A,_,_,_,_,_,_)).
A = [104, 116, 116, 112, _G1205].

I think that part is correct, but now I want to convert the char list into a string, so I changed the last line to this:

end([S]) :-
   string_to_atom([S], K).

But I get this error message:

ERROR: string_to_atom/2: Arguments are not sufficiently instantiated

I'm probably missing something. Can you tell what it is?

repeat
  • 18,496
  • 4
  • 54
  • 166
Jonny
  • 45
  • 5
  • Note that in your "terminal" clause `end(Scheme)` of `scheme/2`, the rule for `end/1` creates a free variable. If that's what you intend, okay, but it seems to be the presence of that free variable causing the error in calling `string_to_atom/2`. Also a good idea is specifying which Prolog you are using, so any possible quirks can be discussed. – hardmath Nov 27 '12 at 14:16
  • What happens if you use: end([S]) :- print(S) – NotAUser Nov 27 '12 at 14:18
  • @hardmath: i'm usign swi-prolog – Jonny Nov 27 '12 at 14:42
  • user1638891: it answer me this ?- scheme("http:", uri(A,_,_,_,_,_,_)). _G2396 A = [104, 116, 116, 112, _G2396] – Jonny Nov 27 '12 at 15:01
  • the problem seem to be the last char 152 ?- string_to_atom([104, 116, 116, 112, _G1211], K). ERROR: string_to_atom/2: Arguments are not sufficiently instantiated i have to find out what is this "_G1211", any idea? it cant be the ':' right? – Jonny Nov 27 '12 at 16:17
  • That is how SWI Prolog displays a free variable, `_Gnnnn`. I believe as noted above that this is the result of how you bind `Scheme` in your terminal case of parsing the URI, by calling `end/1`. That call succeeds with a free variable `S` making the last entry in your string/list of character codes. Thus my question as to whether this is really what you want at the end of the string/list of character codes. – hardmath Nov 27 '12 at 17:01
  • Possibly what you really want is `end([ ])`, i.e. to complete the list with an empty tail? – hardmath Nov 27 '12 at 17:02
  • 2
    headGetter???? not in Prolog, please! – CapelliC Nov 27 '12 at 17:52
  • You get _Gxxxx because at the first call of scheme(T, uri(This, Userinfo, Host, Port, Path, Query, Fragment)), This is unified with nothing. Trace H and This in the this rule of scheme. – joel76 Nov 28 '12 at 13:40

1 Answers1

0

A string in Prolog is just a list of character codes, then you can simplify your code a lot: consider that

?- S = "http:/example.com", append(L, [0':|R], S), format('~s and ~s~n', [L,R]).

will output

http and /example.com
S = [104, 116, 116, 112, 58, 47, 101, 120, 97|...],
L = [104, 116, 116, 112],
R = [47, 101, 120, 97, 109, 112, 108, 101, 46|...] .

colonCheck/1,headGetter/2,end/1 are useless, I think it's bad style in any language, and specially in declarative languages, introducing symbols without need.

If you need to parse structured data, you'll find better support from DCG:

?- phrase((seq(L),":",seq(R)), "http:/example.com", []),format('~s and ~s~n', [L,R]).

where

seq([]) --> [].
seq([C|Cs]) --> [C], seq(Cs).

will output the same as above, i.e.

http and /example.com
L = [104, 116, 116, 112],
R = [47, 101, 120, 97, 109, 112, 108, 101, 46|...] .

bottom line: replace scheme/2 with

scheme(Url, uri(Scheme, _Userinfo, _Host, _Port, _Path, _Query, _Fragment)) :-
    append(Scheme, [0':|_], Url).

and you'll get

?- scheme("http:", uri(A,_,_,_,_,_,_)).
A = [104, 116, 116, 112]
CapelliC
  • 59,646
  • 5
  • 47
  • 90