On mobile and I want to dig into this some more tomorrow but let me start by addressing the last two points.
"Defaulty representation" is described here by Marcus Triska (towards the bottom of the page): https://www.metalevel.at/prolog/data
The terminology of linearizing the arguments I lifted from the SICStus IDE features page: https://sicstus.sics.se/spider/index.html
Thanks again and I'm reviewing your thoughtful comments, thank you again.
The "defaulty representation" Markus Triska discusses is indeed something to be avoided, but if compound terms start to proliferate the chance of typos causing problems like the one you had increases. The solution is ad-hoc typing as recommended by Covington et al.
The balance I think, between a "defaulty representation" and an explosion of "magic strings" is to make sure there are only a handful of predicates that expect their arguments to be typed as compound terms and that those predicates are at the base of a hierarchy of calls that pass those arguments around. Those predicates are responsible for reasoning about those typed arguments and they raise errors if something is off. That way you know quickly when there's a mistake, and where it is.
Another thing to keep in mind is that it's easy to test your Prolog predicates in isolation and check that they do what you think they do. This is the best way to catch errors that have to do with argument structure. What I mean is that you can run each predicate on its own, without having to start from the top of your program. You go to your repl and make some queries to the predicate you want to test with different arguments and see how it behaves. That will help catch errors. Unit tests can also help, if you have the patience to write them.
To be honest, I'm not going to defend Prolog for making this kind of thing easy to hurt yourself with. I love Prolog but it's not friendly to newcomers, exactly because of things like that, which you only learn with experience. Even now, after using it for ... 14 years or so, it still finds ways to hurt me. You gotta be careful with it.
Linearize Arguments
Ensures that each argument position is a variable that does not occur elsewhere in the clause head. As an example,
foo(a, p(X1), X) :-
body(a, X2, X2).
would become:
foo(A, A1, X) :-
A = a,
A1 = p(X1),
body(a, X2, X2).
https://sicstus.sics.se/spider/tips.htmlI'm really enjoying the convington et al read, cool to see that O'Keefe is an author too!
Let me see if I can apply flattening to the example above:
% Flattened version:
foo(a, A1, X) :-
q(A1)
,body(A, X2, X2).
q(p(X1)):-
% ... code that binds X1
.
With flattening only compound terms are replaced, not constants so "a" remains unchanged. It's similar to an ad-hoc type system again, but the cool thing is that it can be done automatically. There's an algorithm for it known to the Inductive Logic Programming (ILP) community. Let me see if I can find that paper... Yep:Flattening and Saturation: Two Representation Changes for Generalization, Céline Rouveirol, 1994.
https://link.springer.com/content/pdf/10.1023/A:102267821728...
The example is a bit unusual though because it only checks that A1 = p(X1) and doesn't do anything with X1, it even leaves it dangling as a singleton; same with X and X2. That's very unlikely for real-world code where you want to use unification as a mechanism to pass the state of the computation around your program. With flattening you want to have an extra argument in the new predicate that "returns" a value that you want to process further. I think maybe they meant to write it like this:
foo(a, p(X1), X) :-
body(a, X1, X).
foo(A, A1, X) :-
A = a,
A1 = p(X1),
body(a, X1, X).
In which case the flattened version would be like: foo(a, A1, X) :-
q(A1,X1),
body(a, X1, X).
q(p(X1),X2):-
% ... code that binds X2
.
So, I guess, we see that this is a known gotcha and the logic programming community has different ways to work around it. In the ILP community there's a different motivation (to make a language finite, and therefore decidable, by removing "functions").>> I'm really enjoying the convington et al read, cool to see that O'Keefe is an author too!
Yeah. I haven't heard much from O'Keefe lately and I miss his advice. He was a regular contributor to the SWI-Prolog mailing list when I was doing my MSc in 2014. I think there was a bit of a problem with the SWI-Prolog community moving to Google and he hasn't returned since, even though the community is now on Discourse.