I think the same. I like most the Haskell syntax, 1%3.
Perhaps the scanner is the easier part to cope with, so… I would vote for %, it has the advantage its use could break ‘nothing more’ than comments
and clueless, sparse, use-once scanners
Handling that in the Prolog parser is not the biggest issue. Otherwise I fear it will break a lot more. I’ve seen enough %-comment without a space in front of it. Also editor support will get tricky. Finally, C-like languages (including Javascript) use x%y as remainder (of division).
There is so far only one example of a breakage. No doubt some more will show up. Load your program and run ?- list_rationals.. If you have no syntax errors while loading and this remains silent you are pretty safe. By default, list_rationals/0 ignores rationals as arguments of arithmetic expressions. I don’t really see how this can break anything, but using this it lists all rationals. If this stays silent, no P/Q term was re-interpreted.
?- list_rationals([arithmetic(true)]).
![]()
I would add also the yyyy-mm-dd works (mostly) seamlessly when talking to easily accessible DBs
That’s a good argument. I will make soon the necessary changes to allow YYYY-MM-DD.
As it’s in particular case in Logtalk documenting directives:
:- info([
version is 1.0,
author is 'Paulo Moura',
date is 2008/3/31,
comment is 'Ackermann function (general recursive function).'
]).
Writing instead date is date(2008,3,31) would be awkward at best.
Continuing testing the latest commits in the rational branch and also doing some comparison testing in ECLiPSe. Will report later.
That makes me wonder if, in alternative, 1|3 could work…
I doubt it. ‘|’ is also used to create terms. Some people like writing [1|3] and finally, some people have a lot of trouble dealing with \, / and |. Let us not make it worse ![]()
That’s why I wrote wonder if 
Anyway, I just experimented starting up Logtalk using both SWI-Prolog rational branch (8.1.21-41-gfd2c60143-DIRTY) and ECLiPSe stable 7.0 #49 version.
SWI-Prolog: Logtalk loads fine with the prefer_rationals flag set to false. Fails to load with the flag set to true.
ECLiPSe: Logtalk loads fine independently of the prefer_rationals flag value (on of off). With the flag turned on, I can still do e.g.
[user 57]: X is 1/2 + 1/5.
X = 7_10
Yes (0.00s cpu)
and load Logtalk source code that uses the YYYY/MM/DD format for dates without issue and without the date being interpreted as a rational term (i.e. YYYY, MM, DD are still parsed as integers).
Needless to say, I prefer ECLiPSe behavior here 
Something odd. gfd2c60143 doesn’t appear in my logs. I’m at version 8.1.21-46-gec0ff5028 ![]()
Then
$ swipl
?- set_prolog_flag(rational_syntax, compatibility).
true.
?- logtalk.
<nice long header>
?- X is 1/2 + 1/5.
X = 7R10.
Instead of compatibility you can also use none. The prefer_rationals only affects arithmetic though and now means the same as its ECLiPSe cousin.
P.S. With 8.1.21-46-gec0ff5028-DIRTY I get when building:
[80/232] Building C object src/CMakeFiles/libswipl.dir/os/pl-prologflag.c.o
../src/os/pl-prologflag.c:1083:7: warning: variable 'v' is used uninitialized whenever switch default is taken [-Wsometimes-uninitialized]
default: assert(0);
^~~~~~~
../src/os/pl-prologflag.c:1086:31: note: uninitialized use occurs here
return PL_unify_atom(val, v);
^
../src/pl-ldpass.h:107:50: note: expanded from macro 'PL_unify_atom'
#define PL_unify_atom(t, a) PL_unify_atom__LD(t, a PASS_LD)
^
../src/os/pl-prologflag.c:1077:13: note: initialize the variable 'v' to silence this warning
{ atom_t v;
^
= 0
1 warning generated.
``
Try 47
I wonder whether gcc is smart enough to see that assert(0) never returns …
Think you’re missing that exactly because it’s at a different ‘syntactic level’ than terms that make it the most interesting I can think of. But of course, Jan W. takes the burden to make the whole working, and that’s the important thing in the end.
Warnings gone ![]()
I like it! A lot! But as Jan noted, it overlaps the list syntax.
About N/M, I would like to have it more for path expressions, could give a taste of object orientation to modules, at source level.
There is nothing that stops you doing so unless you want integers as path segments. Then you still need to be aware of oddities which as /aap/(dynamic)/noot.
Yes, in C++ is overridable. Then a type has a chance to implement a simple DSL that make source less cluttered.
It’s just I would prefer to see / lexicalized in path expressions (enabling OO on modules/files).
Of course, about the breakage % could introduce, I think it has an important property that make it more amenable than /, that is, the surface syntax became invalid… an easy catch, and basically doesn’t require a prolog_flag to control its behaviour.
Of course I do know the basics of path resolution in modules context, but I would like a lot to be able to write lexicalized modules/files names expressions. For instance ?- File=..., open(~/my/folder/File,...), or ?- X/Y/Z:Pred(...)..
Could be done with rewrite, and who knows, maybe in future, a pack will do.
That works fine if you define ~/ as a prefix operator. You, you cannot do this anymore
?- open(~/my/7/3).
Well, you can by examining the ratuional but then 4/2 will open 2/1 ![]()
But you could already not do as below as it would open ‘~/my/2020/2/1’
?- open(~/my/2020/02/01).
Please come with existing code that breaks. Paulo did. 1/3 simply has the preference because it is what most languages do and thus we should only decide otherwise if the price is too high
or it would lead to a whole new class of inconsistencies in the syntax. As it is the same issue as with -, that is not the case. So far YYYY/MM/DD terms are the closest we got. We have also seen that in the light of standards and ambiguity this should be YYYY-MM-DD. It is up to Paulo to (1) disable rationals, (2) support them using the 1R3 syntax (which might still change) or (3) change to YYYY-MM-DD, allow users to use 1/3 and provide some tooling to quickly find and update existing code.
Note that the latter is not so hard: simply accept a term Rat/Int with an informative warning and propose a simple (not tested and may depend on the sed version)
sed -i 's/date\s+is\s+(\d\d\d\d)/(\d\d)/(\d\d)/date is \1-\2-\3' *.lgt
Great! Then open/4 will do automagically resolve $HOME ?
In path expressions, also the dot should regain the binary operator status, for instance ?- edit(file(my_file.pl)) would be nice. Really, just aesthetic preferences … worthless, so sorry for the noise
.
Wow. A lot to catch up on.
I have to admit I’m waffling. I fear that the Logtalk usage of / as a non-arithmetic separator is the tip of the iceberg. There aren’t many characters suitable for generic separators. Others include - : . | \ and most of those have limitations in SWI Prolog syntax (e.g., : would be nice for type systems but is used for module qualification, . for field expressions but used for dictionaries, | in list syntax, etc.) So I have some sympathy for not further restricting the few nice separator characters that are left.
I also tend to think that a single syntax for a rational number, used for both input and output, would be preferable, rather than a variety under configuration control (Eclipse compatibility being an exception). And I’d also like to see something minimal, like the single infix character under discussion.
With that in mind, I’ve started to appreciate the PrQ syntax used in J. J was co-designed by Kenneth Iverson as a successor to APL (without the extended font requirements), so I think it has some credibility even if it isn’t widely used.
PrQ avoids all the issues with pre-existing operators and makes the parsing of things like 1r2.0 a bit more obvious (possibly .(1r2,0) depending on the parsing of . expressions). The use of lowercase characters in numbers has been established (non-decimal radix). Like the infix separator being discussed, it avoids the multi-token lookahead that the Ruby syntax entails.
Given a clean slate, i would still prefer 1/2 but I don’t think we have that luxury.
Agree. In fact, in last hour, I completed changing all dates in the Logtalk distribution source files to ISO 8601 format, update the compiler to support this format as an alternative when type-checking dates in info/1 directives, and run all the tests (close to 6000). Around 20 tests failed due to code using A/B terms as compound terms. For example, I have an eight puzzle formulation where the code includes:
initial_state(four_steps, [2/2,1/3,3/2,2/3,3/3,3/1,2/1,1/1,1/2]).
initial_state(five_steps, [2/1,1/2,1/3,3/3,3/2,3/1,2/2,1/1,2/3]).
initial_state(eighteen_steps, [2/2,2/3,1/3,3/1,1/2,2/1,3/3,1/1,3/2]).
goal_state(goal, [2/2,1/3,2/3,3/3,3/2,3/1,2/1,1/1,1/2]).
print_state([S0,S1,S2,S3,S4,S5,S6,S7,S8]) :-
member(Y, [3, 2, 1]),
nl,
member(X, [1, 2, 3]),
member(Tile-X/Y, [' '-S0,1-S1,2-S2,3-S3,4-S4,5-S5,6-S6,7-S7,8-S8]),
write(Tile),
fail.
print_state(_) :-
nl.
I have a port of ROK code for random number generator that includes the code:
random(A0, A1, A2, B0, B1, B2, Random) :-
B0 is (A0*171) mod 30269,
B1 is (A1*172) mod 30307,
B2 is (A2*170) mod 30323,
Float is A0/30269 + A1/30307 + A2/30323,
Random is Float - truncate(Float).
This particular one is easy to fix. Just change to Float is A0/30269.0 + A1/30307.0 + A2/30323.0. But illustrates what will be a common source of nuisances: (/)/2 no longer returning a float. Note that in general both arguments may only be known at runtime…
Ironically, I have an example of type parameterized sort with one of the example types being rational number represented as A/B. the tests fail as the code contains definitions as:
N1/D1 < N2/D2 :-
{N1*D2 < N2*D1}.
but now:
?- 2/7 = N/D.
false.
You can argue that native support for rational numbers makes the example moot but that’s besides the point: code that is perfectly valid Prolog code no longer works. Btw, ECLiPSe have no issues with the code; all tests pass. There are more failed tests due to A/B no longer resulting in a float. For example:
! population_variance_2_03: failure
! test assertion failed: =~=(1156/5,231.2)
! in file /Users/pmoura/logtalk/library/statistics/tests.lgt between lines 197-198
I also have a port of Ivan Bratko state-space search algorithms that include clauses such as:
search(Space, State, Threshold, Solution, Cost) :-
expand([], l(State, 0/0), Threshold, _, yes, Path, Space, Cost),
list::reverse(Path, Solution).
expand(Path, l(State,Cost/_), _, _, yes, [State|Path], Space, Cost) :-
Space::goal_state(State).
expand(Path, l(State,F/G), Threshold, Tree, Solved, Solution, Space, Cost) :-
F =< Threshold,
( bagof(Next/Cost2, (Space::next_state(State, Next, Cost2), \+ Space::member_path(Next, Path)), Successors) ->
succlist(G, Successors, Trees, Threshold, Space),
bestf(Trees, F2, Threshold),
expand(Path, t(State, F2/G, Trees), Threshold, Tree, Solved, Solution, Space, Cost)
; Solved = never
).
succlist(_, [], [], _, _).
succlist(G0, [State/Cost| Rest], Trees, Threshold, Space) :-
G is G0 + Cost,
Space::heuristic(State, H),
F is G + H,
succlist(G0, Rest, Trees2, Threshold, Space),
insert(l(State, F/G), Trees2, Trees, Threshold).
Note the State/Cost term in the last predicate.
So, in just the above examples, we haver code from three different authors (myself, ROK, and Ivan Bratko; hey! I’m in good company
) using A/B as a compound term or expecting A/B to evaluate always to a float.
I don’t mind (in fact, I already did the work) of switching to the ISO 8601 format for dates. But that is not what worries me in the proposed “natural” representation for rational numbers.