3
votes

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?

1
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
What happens if you use: end([S]) :- print(S)NotAUser
@hardmath: i'm usign swi-prologJonny
user1638891: it answer me this ?- scheme("http:", uri(A,,,,,,)). _G2396 A = [104, 116, 116, 112, _G2396]Jonny
headGetter???? not in Prolog, please!CapelliC

1 Answers

0
votes

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]