Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Towards OS Polyglott Prolog Systems

29 views
Skip to first unread message

Mostowski Collapse

unread,
May 24, 2022, 6:19:25 AM5/24/22
to
I noticed that in my new Dogelog Player the absolute_file_name/2
predicate might either return one of the two:

/* WSL */
?- absolute_file_name('baz.p', X).
X = '/mnt/c/foo/bar/baz.p'

/* Windows 10 */
?- absolute_file_name('baz.p', X).
X = 'C:\\foo\\bar\\baz.p'

So what to do? Normalize it and always use '/' and eliminate '\\' ?
This is what I did for formerly Jekejeke Prolog.

How do everything 100% in Prolog?

Mostowski Collapse

unread,
May 24, 2022, 6:22:35 AM5/24/22
to
Here comes last_sub_atom/5 to the rescue. The proposal is simple.
sub_atom/5 search forward, last_sub_atom/5 searches backward:

Here from ISO core standard:

?- sub_atom('baaab', X, Y, Z, 'aa').
X = 1, Y = 2, Z = 2;
X = 2, Y = 2, Z = 1;
fail.

?- sub_atom('abracadabra', X, Y, Z, 'abra').
X = 0, Y = 4, Z = 7;
X = 7, Y = 4, Z = 0.

And here the analogue searching backward:

?- last_sub_atom('baaab', X, Y, Z, 'aa').
X = 2, Y = 2, Z = 1;
X = 1, Y = 2, Z = 2;
fail.

?- last_sub_atom('abracadabra', X, Y, Z, 'abra').
X = 7, Y = 4, Z = 0;
X = 0, Y = 4, Z = 7.

I introduced this some years ago in formerly Jekejeke Prolog.
And since this week its also available in Dogelog Player.

Mostowski Collapse

unread,
May 24, 2022, 6:27:17 AM5/24/22
to
Here is a use case for last_sub_atom/5. Its useful to make an OS polyglott
Prolog system, at least polyglott among Unix, Windows and Mac. You
can get rid of Logtalks internal_os_path/2, which I think is a little

design flaw in my old Prolog system, which my new Prolog system tries
to avoid. One can do the following like here, maybe there are also other
agorithms based on last_sub_atom/5, but this is easiest to understand:

sys_file_parent(Path, Dir) :-
(last_sub_atom(Path, Pos1, _, _, '/') -> true; Pos1 = -1),
(last_sub_atom(Path, Pos2, _, _, '\\') -> true; Pos2 = -1),
Pos is max(Pos1, Pos2), Pos \== -1, !,
Pos3 is Pos+1,
sub_atom(Path, 0, Pos3, _, Dir).
sys_file_parent(_, '').

sys_file_name(Path, Name) :-
(last_sub_atom(Path, Pos1, _, _, '/') -> true; Pos1 = -1),
(last_sub_atom(Path, Pos2, _, _, '\\') -> true; Pos2 = -1),
Pos is max(Pos1, Pos2), Pos \== -1, !,
Pos3 is Pos+1,
atom_length(Path, Len),
Len2 is Len-Pos3,
sub_atom(Path, Pos3, Len2, _, Name).
sys_file_name(Path, Path).

Maybe regex could do the same. But can regex search backwards?
You would need a kind of greedy regex pattern, that nevertheless
has an alternative in it. And a regex library is more heavier, than some

last_sub_atom/5 which is still relative lightweight to provide, only
a variant of sub_atom/5.

Mostowski Collapse

unread,
May 24, 2022, 6:43:49 AM5/24/22
to
Here are some example runs:

?- sys_file_parent('/mnt/c/foo/bar/baz.p', X).
X = '/mnt/c/foo/bar/'.

?- sys_file_name('C:/foo/bar/baz.p', X).
X = 'baz.p'.

?- sys_file_parent('C:\\foo\\bar\\baz.p', X).
X = 'C:\\foo\\bar\\'.

?- sys_file_name('C:\\foo\\bar\\baz.p', X).
X = 'baz.p'.

Its not the same as decompose_file_name/3 from Logtalk,
which is possibly also not OS polyglott. Its not the same
since it leaves the directory delemiter, either '/' or '\\'

at the end of the parent intact. So the reverse function
of this decomposition is simply atom_concat/3:

?- atom_concat('/mnt/c/foo/bar/', 'baz.p', X).
X = '/mnt/c/foo/bar/baz.p'.

?- atom_concat('C:\\foo\\bar\\', 'baz.p', X).
X = 'C:\\foo\\bar\\baz.p'.

Mostowski Collapse schrieb:

Aleksy Grabowski

unread,
May 24, 2022, 3:35:42 PM5/24/22
to
Hello,

Why you didn't decide to use more classic dirname and basename? Meaning
would've been immediately obvious for any experienced programmer.

Best Regards,
Alex

Mostowski Collapse

unread,
May 25, 2022, 5:29:57 PM5/25/22
to
Its different from dirname. The predicate sys_file_parent/2
gives a slashified directory:

?- sys_file_parent('/mnt/c/foo/bar/baz.p', X).
X = '/mnt/c/foo/bar/'.

Whareas the usual dirname would give it without slash.

?- file_directory_name('/mnt/c/foo/bar/baz.p', X).
X = '/mnt/c/foo/bar'.

file_directory_name/2 exits already in SWI-Prolog. But
it is not OS Polyglott:

?- file_directory_name('C:\\foo\\bar\\baz.p', X).
X = ('.').

Aleksy Grabowski schrieb:

Mostowski Collapse

unread,
May 30, 2022, 3:54:18 AM5/30/22
to
Question of the day:

> Look-ahead might not be a bad idea?

Rather an pretty bad idea without any benefit, since
the intended use case of non-det last_sub_atom/5, is
det lastIndexOf(_), namely like here, slightly optimized

version now with only one clause:

sys_file_name(Path, Name) :-
atom_length(Path, Len),
(last_sub_atom(Path, _, _, Pos1, '/') -> true; Pos1 = Len),
(last_sub_atom(Path, _, _, Pos2, '\\') -> true; Pos2 = Len),
Pos is min(Pos1, Pos2),
sub_atom(Path, _, Pos, 0, Name).

So there is a (->)/2, which cuts away last_sub_atom/5. So if
you do some extra work in last_sub_atom/5, you will:

- Not eliminate the choice point. For example if the file
name is "foo/bar/baz.p", the look ahead will find another
“/”, and you will get a choice point.

- Only generate overhead. Since you will internally search
the first “/” from left, and then the second “/” from left.

The only thing that removes the choice point is the
local cut in (->)/2. And one way to avoid some extra work
is to not have look-ahead.

Mostowski Collapse

unread,
May 30, 2022, 3:59:24 AM5/30/22
to
BTW, its utterly trivial to implement last_sub_atom/5.
Just copy paste the implementation of sub_atom/5, and
change ++ into --, <= text.length into \>= 0, etc...

Extremly straight forward. Costs you less than a day.


Mostowski Collapse schrieb:
0 new messages