6 ms·
If you're not trying to make your programs as close to logic as possible (that is, support as many modes as possible and make it so you can model your program a
by superdisk 3y ago
If you're not trying to make your programs as close to logic as possible (that is, support as many modes as possible and make it so you can model your program as a logical expression) then what's even the point of using Prolog? Settling for having to reimplement the same logic in multiple directions completely defeats the purpose, you're just writing imperative code at that point.
I think "pragmatic therefore non-logical" versus "ivory tower therefore useless" is a false dichotomy. In my experience it's nearly impossible to make green cuts, and once you know a few tricks and rules of thumb, you can get pretty far writing logical code.
- falsissime 3y agoSupport of as many modes as possible is an aim that is often too ambitious. Instead, unsupported modes should be indicated with an instantiation error or (much rarer) an uninstantiation_error. In this manner the logic remains intact as long as no error occurs and the program does not loop. And yes, this may come at the expense of its usefulness, think of (is)/2. YeGoblynQueenne omitted what the mode +,- actually means. And the program does not check it. Does it mean that the first argument must be ground or is it OK, to leave some variables inside? Think of `[a,f(X),b]`. Also the - has sometimes the meaning of being descriptive (that is a completely steadfast argument) or prescriptive (meaning that the program may be incorrect if the argument is not an unaliased variable). Would errors be used for the unintended cases things would be much clearer.
- YeGoblynQueenne 3y agoGood points and I have to hang my head in shame. Prolog doesn't enforce mode declarations in documentation and I don't either, most of the time, in my code. I also use modes imprecisely and never define them, before I use them, in my documentation, which if anyone ever looks at my code and tries to run it, would create confusion. For instance, I use "-" to indicate both a term that's an unbound variable on entry and one that can be partially instantiated on entry. Obviously that will cover different behaviour in different programs. That's not very nice of me. At least, since I've been bitten many times myself by this I try to document the structure of arguments and to give an example or two of calling in different modes, when that is not too hard to do. I've been complimented many times about the good documentation of my projects, but I feel so embarrassed when people do that. My documentation sucks. It's worse to have half-done documentation than to have no documentation at all :(
- falsissime 3y agoExplicit checking of the appropriate instantiations is something for more or less official interfaces, not for every internal predicate. For those official checking via must_be/2, can_be/2 and the library(si) (all in Scryer) is often all you need. (The SWI-version conflates must_be/2 and can_be/2). But you could save your beloved cut with minimal effort by using dif_si/2 (voir https://stackoverflow.com/a/20238931/772868 https://stackoverflow.com/a/20238931/772868) just before the cut. In this manner you would get instantiation errors for exactly the cases you cannot handle.
- YeGoblynQueenne 3y ago>> Explicit checking of the appropriate instantiations is something for more or less official interfaces, not for every internal predicate. But there's no formal concept of "interface" in Prolog, and the module system sucks (or doesn't exist, depending on implementation) and many programs don't ever use it anyway, so instantiations errors are a possible issue at every level of a program. For me at least it's a constant headache knowning how a predicate must be called (hence my practice of documenting the structure of inputs and outputs carefully). I really don't like the ad-hoc "type" checking in Prolog (as in integer/1 etc). Prolog doesn't have types, because pre-Church logic doesn't have types (and post-Church logic is a mess; typed mess, but still a mess). And yet Prolog terms (in the sense of a functor followed by comma-separated terms in parentheses) are implicitly typed, under unification: T is the type of all terms that unify with T. So making sure that terms are correctly instantiated is the most prudent thing to do when checking the "type" of a term. Unfortunately that adds too much clutter and I personally resent havng to do it. I have seen various attempts to solve that conundrum over the years, for example there's a package for SWI-Prolog that adds Hindley-Milner type checking (brrr). I don't like any of them. It's a bit weird how that is the kind of thing that Prolog gets wrong that I rarely hear as an actual criticism, as opposed to complaints about the cut, or the imperfect declarative-ness. I guess all this would be solved in practice by the addition of a static type system, checked at compile time, which would completely change the language of course. Incidentally, I'm currently working on an ancient (30 years old) Visual Prolog project; Visual Prolog is exactly that, a compiled Prolog with a static type system. I feel that while it sure helps catch some errors, it contrives to suck all the energy and life out of Prolog. Prolog is like parcour: it lets you fly around town, jumping and rolling like Spiderman. So sometimes you get a lamppost en plein dans la figure. So what. Who needs type safety anyway? (She says while changing yet another bloody bandage) >> But you could save your beloved cut with minimal effort by using dif_si/2 (voir https://stackoverflow.com/a/20238931/772868 https://stackoverflow.com/a/20238931/772868) just before the cut. In this manner you would get instantiation errors for exactly the cases you cannot handle. Thanks for the pointer. I had a quick look. I think there's something similar in SWI-Prolog's Picat-style matching with the "=>" operator that is an alternative to ":-". I'm not sure exactly what it does (something about "steadfastness", that you also mentioned, and that is a new term for me) but I prefer to not use libraries that significantly change standard Prolog syntax, for fear of backwards compatibility.
- YeGoblynQueenne 3y agoWhat's the point of using Prolog? I like it. I mean, I don't have any rational reasons. I could try to find some but I'd just be rationalising. The things that most people consider advantages or disadvantages, I couldn't care less about. Take declarativeness for example- writing declarative code is just not something I care deeply about. Nor is being able to run code both ways. I don't care about that stuff. I just like writing my code in Prolog [1]. Of course, if you do care about being able to code declaratively, or logically, then Prolog is your best chance. Prolog is maybe 90% purely declarative. You can write your programs so they run in all modes easily maybe 60% of the time. Try getting anywhere close to either of that in any other language. The reason people oversell Prolog with "you can run your code backwards" is that you can do that at all in Prolog, but not in other languages. As to "make your programs as close to logic as possible" - well, you can't. Logic is not a programming paradigm. Logic programming is. FOL says nothing about programs. Logic programming does. FOL doesn't even say anything about proofs. That's how logic works: you have your clean and tidy syntax rules and everything else is semantics. Now, Logic Programming, that's a semantics for FOL on computers. Like I say in another comment, logic programming begins and ends with Robinson's Resolution principle [2]. That's the theory of logic programming, or in any case Resolution-based logic programming (hi ASP folks!). Prolog is an implementation of Resolution. The implementation is not perfect, but I'm fine with that, as long as I know I can count on the theory to be well-formed. If the theory is good, the implementation can do whatever it likes. At some point, if there is a real need, someone will come up with a better one. So far, I don't see anyone making a better Resolution implementation than Prolog. So I don't think it's needed. I think Prolog is just fine the way it is. _________ [1] Not just Prolog, of course. Then again, last time I had to write a substantial bit of Python I found, to my horror, that I have turned to the proverbial FORTRAN programmer who can write FORTRAN in any language; except s/FORTRAN/Prolog/g. By which I mean my Python code looked just like my Prolog code. I may have lost the ability to write anything but Prolog, after writing almost all my stuff in Prolog for the last five years or so. Well at least it didn't happen with R... [2] I know that is a disservice to all the people who worked on automated theorem proving and logic programming before and after Robinson, but I'm going through a bit of a phase where I am in awe of what Robinson achieved, and I think of him as the god of logic programming, more or less. I'll get over it.
- YeGoblynQueenne 3y ago>> I think "pragmatic therefore non-logical" versus "ivory tower therefore useless" is a false dichotomy. In my experience it's nearly impossible to make green cuts, and once you know a few tricks and rules of thumb, you can get pretty far writing logical code. I don't agree that it's hard to make green cuts. The standard ones are, in recursive programs, one in the terminating condition of a recursive program and one in every recursive clause after the last. Ideally those should be placed immediately after the goal in the relevant clause acting as a "test" to select the clause, as advised by Covington et al (https://www.covingtoninnovations.com/mc/plcoding.pdf https://www.covingtoninnovations.com/mc/plcoding.pdf; much sensible advise on using the cut there, too). Those cuts are "green" as a rule (there will be exceptions) in that they avoid unnecessary backtracking after a condition is met for selecting the clause. But of course those cuts can be misused to hide a programming error. That is something the programmer must learn to avoid, but I really don't see that as an insurmountable obstacle. To come back to Covington et al: 5.5 Never add a cut to correct an unknown problem A common type of Prolog programing error is manifested in a predicate that yields the right result on the first try but goes wrong upon backtracking. Rather than add a cut to eliminate the backtracking, investigate what went wrong with the logic. There is a real risk that if the problem is cured by adding the cut, the cut will be far away from the actual error (even in a different predicate), which will remain present to cause other problems later. And btw, "pragmatic" doesn't have to be "non-logical". I'm not arguing about that. I'm claiming that the purity of FOL is unreachable in the real world and concessions have to be made. At the end of the day, sloppy coding is sloppy coding, whether it's pragmatic, or pure, or declarative, or whatever and I'm definitely not advocating for writing code in any old way.